//这个题做的蛋疼,,,自己的想法就是不对,归根结底还是对最大流这种基本的东西不熟悉,,它的内涵都不懂,自己真是水呀
//我第一想的办法是把regulator[]当做限制,WA,原因没分析到,这是WA代码
using namespace std;
const int MAX=105,INF=1<<30;
int regulator[MAX],m,cap[MAX][MAX],flow[MAX][MAX],
startN,sink,t,a[MAX],n,p[MAX];
queue<int> q;
int smallest(int i,int j,int k){
int s=i<j?i:j;
return s<k?s:k;
}
int maxFlow(){
memset(flow,0,sizeof(flow));
int f=0,u;
while(1){
memset(a,0,sizeof(a));//a代表指向结点[v]的增广路
a[0]=INF;
q.push(0);
//cout<<"s: "<<endl;
while(!q.empty()){
u=q.front(); q.pop();
//cout<<u<<" "<<a[u]<<endl;
for(int v=1;v<=n;v++){
if(!a[v]&&cap[u][v]>flow[u][v]&&
regulator[v]>flow[u][v]){
p[v]=u; q.push(v);
//if(v==1)
// cout<<"ssssssssss: "<<u
// <<" "<<flow[u][v]<<endl;
a[v]=smallest(a[u],cap[u][v]-flow[u][v],
regulator[v]);
//regulator[v]-=a[v];
}
}
}
if(!a[t])
break;
//cout<<a[t]<<endl;
for(u=t;u!=0;u=p[u]){
flow[p[u]][u]+=a[t];//从汇点开始更新正向流
flow[u][p[u]]-=a[t];//从汇点开始更新反向流
//regulator[u]-=a[t];//从汇点开始更新regulator
}
f+=a[t];
}
return f;
}
int main()
{
freopen("i.txt","r",stdin);
int v1,v2,w;
regulator[0]=INF;
while(cin>>n){
memset(cap,0,sizeof(cap));
for(int i=1;i<=n;i++)
cin>>regulator[i];
cin>>m;
for(int i=0;i<m;i++){
cin>>v1>>v2>>w;
cap[v1][v2]=w;
}
cin>>startN>>sink;
//cout<<startN<<" "<<sink<<endl;
for(int i=0;i<startN;i++){
cin>>v1;
//cout<<v1<<endl;
cap[0][v1]=INF;
}
t=++n;
regulator[t]=INF;
for(int i=0;i<sink;i++){
cin>>v1;
cap[v1][t]=regulator[v1];
}
cout<<maxFlow()<<endl;
}
return 0;
}
//然后我又想到了一个优化 就是两个点之间的容量cap只能是它u,v,的regulator 和他们边的cap的最小值,,结果居然水过去了,代码如下
using namespace std;
const int MAX=105,INF=1<<30;
int regulator[MAX],m,cap[MAX][MAX],flow[MAX][MAX],
startN,sink,t,a[MAX],n,p[MAX];
queue<int> q;
int smallest(int i,int j,int k){
int s=i<j?i:j;
return s<k?s:k;
}
int maxFlow(){
memset(flow,0,sizeof(flow));
int f=0,u;
while(1){
memset(a,0,sizeof(a));//a代表指向结点[v]的增广路
a[0]=INF;
q.push(0);
while(!q.empty()){
u=q.front(); q.pop();
for(int v=1;v<=n;v++){
if(!a[v]&&cap[u][v]>flow[u][v]){
p[v]=u; q.push(v);
a[v]=a[u]<cap[u][v]-flow[u][v]?
a[u]:cap[u][v]-flow[u][v];
//regulator[v]-=a[v];
}
}
}
if(!a[t])
break;
//cout<<a[t]<<endl;
for(u=t;u!=0;u=p[u]){
flow[p[u]][u]+=a[t];//从汇点开始更新正向流
flow[u][p[u]]-=a[t];//从汇点开始更新反向流
//regulator[u]-=a[t];//从汇点开始更新regulator
}
f+=a[t];
}
return f;
}
int main()
{
freopen("i.txt","r",stdin);
int v1,v2,w;
regulator[0]=INF;
while(cin>>n){
memset(cap,0,sizeof(cap));
for(int i=1;i<=n;i++)
cin>>regulator[i];
cin>>m;
for(int i=0;i<m;i++){
cin>>v1>>v2>>w;
cap[v1][v2]=smallest(w,regulator[v1],regulator[v2]);
}
cin>>startN>>sink;
//cout<<startN<<" "<<sink<<endl;
for(int i=0;i<startN;i++){
cin>>v1;
//cout<<v1<<endl;
cap[0][v1]=regulator[v1];
}
t=++n;
regulator[t]=INF;
for(int i=0;i<sink;i++){
cin>>v1;
cap[v1][t]=regulator[v1];
}
cout<<maxFlow()<<endl;
}
return 0;
}
//最后才是对的做法,,就是拆点,,其实我第一个思路就是这个,只是当时觉得麻烦没写,其实一点都不麻烦
using namespace std;
const int MAX=105*2,INF=1<<30;
int regulator[MAX],m,cap[MAX][MAX],flow[MAX][MAX],
startN,sink,t,a[MAX],n,p[MAX],
head[MAX],rear[MAX],dian;
queue<int> q;
int maxFlow(){
memset(flow,0,sizeof(flow));
int f=0,u;
while(1){
memset(a,0,sizeof(a));//a代表指向结点[v]的增广路
a[0]=INF;
q.push(0);
while(!q.empty()){
u=q.front(); q.pop();
for(int v=1;v<=n;v++){
if(!a[v]&&cap[u][v]>flow[u][v]){
p[v]=u; q.push(v);
a[v]=a[u]<cap[u][v]-flow[u][v]?
a[u]:cap[u][v]-flow[u][v];
//regulator[v]-=a[v];
}
}
}
if(!a[t])
break;
//cout<<a[t]<<endl;
for(u=t;u!=0;u=p[u]){
flow[p[u]][u]+=a[t];//从汇点开始更新正向流
flow[u][p[u]]-=a[t];//从汇点开始更新反向流
//regulator[u]-=a[t];//从汇点开始更新regulator
}
f+=a[t];
}
return f;
}
int main()
{
freopen("i.txt","r",stdin);
int v1,v2,w;
regulator[0]=INF;
while(cin>>n){
dian=1;
memset(cap,0,sizeof(cap));
for(int i=1;i<=n;i++){
cin>>regulator[i];
head[i]=dian; rear[i]=dian+1;
cap[dian][dian+1]=regulator[i];
dian+=2;
}
cin>>m;
for(int i=0;i<m;i++){
cin>>v1>>v2>>w;
cap[rear[v1]][head[v2]]=w;
}
cin>>startN>>sink;
//cout<<startN<<" "<<sink<<endl;
for(int i=0;i<startN;i++){
cin>>v1;
//cap[0][v1]=regulator[v1];
cap[0][head[v1]]=INF;
}
//t=++n;
t=n=dian;
//regulator[t]=INF;
for(int i=0;i<sink;i++){
cin>>v1;
//cout<<v1<<endl;
cap[rear[v1]][t]=INF;
}
/*for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cout<<cap[i][j]<<" ";
}
cout<<endl;
}*/
cout<<maxFlow()<<endl;
}
return 0;
}
//为什么我第2种方法是错的,第3种是对的呢?,可以看一下数据
8
20 15 17 5 10 25 20 50
10
1 4 15
1 5 5
2 5 10
2 6 10
3 6 25
6 5 10
4 7 10
5 7 15
5 8 10
6 8 15
3 2
1 2 3 7 8
5
20 15 10 20 20
4
1 3 5
2 3 10
3 4 10
3 5 10
2 2
1 2 4 5
//如果你仔细分析最后一个数据的结点5,你会发现第2种方法忽略了结点5的regulator是10的限制而让5结点流出了 15的流量