hdu2686/hdu3376 最小费用流最大流 拆点
虽然题目求的是最大费用,但是我们可以通过转换就变为最小费用。用一个比最大值更的数与每个数的差作为费用值。最后处理回来就i可以了。有些人用直接每个值都乘以-1,这样更简单。
做这题,我对为什么不拆点就会错这个问题想了很久,也问了一些人。最后得出了一些知识。
在《挑战程序设计竞赛》的214页有讲。
点有容量限制,就必须拆点来实现。
3
1 1 0
1 1 1
0 1 1
在这组数据中,我们按从左到右,从上到下的顺序标出点的序号。
1 → 2 3
↓ ↓
4 → 5 → 6
↓ ↓
7 8 → 9
不拆点建图,是有两条路径的。但是5这个点被经过了2次,只有一条路径。点只能经过一次没有体现出来。
所以需要拆点。怎么拆了?像这样。
1 → 2 3
↓ ↓
4 → 5
↓
10→ 6
↓ ↓
7 8 → 9
这样5 → 10的容量限制为1时,就能限制5这个点的容量为1了。
下面是hdu3376的代码:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<queue> 5 #include<algorithm> 6 using namespace std; 7 const int N =1000010, M=4000100,INF=0x3f3f3f3f; 8 struct node 9 { 10 int to, next, c ,f;//c是容量,f是费用 11 }edge[M]; 12 int head[N],dis[N],load[N],p[N]; 13 bool vis[N]; 14 int tot,flow,cost; 15 bool spfa(int S, int E,int n) 16 { 17 queue<int > que; 18 memset(vis,0,sizeof(vis)); 19 memset(load,-1,sizeof(load)); 20 memset(p,-1,sizeof(p)); 21 for(int i=0;i<=n;i++) 22 dis[i]=INF; 23 que.push(S); 24 dis[S]=0; 25 vis[S]=1; 26 while(!que.empty()) 27 { 28 int u=que.front(); 29 que.pop(); 30 vis[u]=0; 31 for(int i=head[u];i!=-1;i=edge[i].next) 32 { 33 if(edge[i].c) 34 { 35 int v=edge[i].to; 36 if(dis[v]-dis[u]>edge[i].f) 37 { 38 dis[v]=dis[u]+edge[i].f; 39 p[v]=u; 40 load[v]=i; 41 if(!vis[v]) 42 { 43 vis[v]=1; 44 que.push(v); 45 } 46 } 47 } 48 } 49 } 50 if(dis[E]==INF) return 0; 51 return 1; 52 } 53 void MCF(int S, int E,int n) 54 { 55 int u,mn; 56 flow=cost=0; 57 while(spfa(S,E,n)) 58 { 59 u=E; mn=INF; 60 while(p[u]!=-1) 61 { 62 mn=min(edge[load[u]].c, mn); 63 u=p[u]; 64 } 65 u=E; 66 while(p[u]!=-1) 67 { 68 edge[load[u]].c-=mn; 69 edge[load[u]^1].c+=mn; 70 u=p[u]; 71 } 72 cost+=dis[E]*mn; 73 flow+=mn; 74 } 75 } 76 void addedge(int a,int b,int c,int d) 77 { 78 edge[tot].to=b;edge[tot].c=c;edge[tot].f=d; 79 edge[tot].next=head[a];head[a]=tot++; 80 edge[tot].to=a;edge[tot].c=0;edge[tot].f=-d; 81 edge[tot].next=head[b];head[b]=tot++; 82 } 83 void init() 84 { 85 tot=0; 86 memset(head,-1,sizeof(head)); 87 } 88 int nd[N]; 89 int main() 90 { 91 //freopen("test.txt","r",stdin); 92 int n,i,j,k,a,s,e,b; 93 while(scanf("%d",&n)!=EOF) 94 { 95 init(); 96 b=n*n; 97 s=2*b+1;e=s+1; a=100; 98 for(i=1;i<=b;i++) {scanf("%d",&nd[i]);a=max(a,nd[i]);} 99 a++; 100 addedge(s,1,2,0); 101 addedge(2*b,e,2,0); 102 for(i=1;i<=b;i++) 103 { 104 if(i==1) addedge(i,i+b,2,a-nd[i]); 105 else if(i==b) addedge(i,i+b,2,a-nd[i]); 106 else addedge(i,i+b,1,a-nd[i]); 107 if(i%n) addedge(i+b,i+1,1,0);//向右 108 if(i<=b-n) addedge(i+b,i+n,1,0);//向下 109 } 110 MCF(s,e,e); 111 cost-=a-nd[1]+a-nd[b]; 112 int ans=4*a*(n-1)-cost; 113 printf("%d\n",ans); 114 } 115 return 0; 116 }