专题十一 网络流

专题链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=68128#overview

网络流基础知识:http://www.cnblogs.com/yaoyueduzhen/p/5020722.html

本专题考察网络流问题, 包含最大流和最小费用最大流,请使用高效模板。

 

A.  poj3436    ACM Computer Factory

分析:这个是一个网络流,对流过每个点的流量有限制,这样就需要拆点,把每个结点拆成两个,一个入点,一个出点,并从入点到出点连接一条边流量为点的的流向限制,把所有接入该点的边接入它的入点,从该点流出的边从出点流出。

建图方法,每个机器是一个点,把源与所有没有必须元件的点连接,所有完整元件的点与汇连接,若一台机器的输出能符合另一台机器的输入条件则连一条边。把每个机器拆点,其内部边流量为其生产速度。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<cstring>
  5 
  6 using namespace std;
  7 const int MAXN=120;
  8 const int MAXM=120*120;
  9 const int INF=0x3f3f3f3f;
 10 int p,n;
 11 int q[MAXN];
 12 int in[MAXN][MAXN],out[MAXN][MAXN];
 13 
 14 struct Edge 
 15 {
 16     int to, next, cap, flow;
 17 }edge[MAXM];
 18 int tol;
 19 int head[MAXN];
 20 void init() 
 21 {
 22     tol = 2;
 23     memset(head, -1, sizeof(head));
 24 }
 25 void addedge(int u, int v, int w, int rw=0) 
 26 {
 27     edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0;
 28     edge[tol].next = head[u]; head[u] = tol++;
 29     edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0;
 30     edge[tol].next = head[v]; head[v] = tol++;
 31 }
 32 int Q[MAXN];
 33 int dep[MAXN], cur[MAXN], sta[MAXN];
 34 bool bfs(int s, int t, int n) 
 35 {
 36     int front = 0, tail = 0;
 37     memset(dep, -1, sizeof(dep));
 38     dep[s] = 0;
 39     Q[tail++] = s;
 40     while(front < tail)
 41     {
 42         int u = Q[front++];
 43         for(int i = head[u]; i != -1; i = edge[i].next) 
 44         {
 45             int v = edge[i].to;
 46             if(edge[i].cap > edge[i].flow && dep[v] == -1)                 
 47             {
 48                 dep[v] = dep[u] + 1;
 49                 if(v == t) return true;
 50                 Q[tail++] = v;
 51             }
 52         }
 53     }
 54     return false;
 55 }
 56 
 57 int dinic(int s, int t, int n) 
 58 {
 59     int maxflow = 0;
 60     while(bfs(s, t, n)) 
 61     {
 62         for(int i = 0; i < n; i++) cur[i] = head[i];
 63         int u = s, tail = 0;
 64         while(cur[s] != -1)
 65         {
 66             if(u == t) 
 67             {
 68                 int tp = INF;
 69                 for(int i = tail-1; i >= 0; i--)
 70                     tp = min(tp, edge[sta[i]].cap-edge[sta[i]].flow);
 71                 maxflow+=tp;
 72                 for(int i = tail-1; i >= 0; i--) 
 73                 {
 74                     edge[sta[i]].flow+=tp;
 75                     edge[sta[i]^1].flow-=tp;
 76                     if(edge[sta[i]].cap-edge[sta[i]].flow==0)
 77                         tail = i;
 78                 }
 79                 u = edge[sta[tail]^1].to;
 80             }
 81             else 
 82                 if(cur[u] != -1 && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] + 1 == dep[edge[cur[u]].to]) 
 83                 {
 84                     sta[tail++] = cur[u];
 85                     u = edge[cur[u]].to;
 86                 }
 87                 else 
 88                 {
 89                     while(u != s && cur[u] == -1)
 90                         u = edge[sta[--tail]^1].to;
 91                     cur[u] = edge[cur[u]].next;
 92                 }
 93         }
 94     }
 95     return maxflow;
 96 }
 97 
 98 int main()
 99 {
100     scanf("%d%d",&p,&n);
101     init();
102     for(int i=1;i<=n;++i)
103     {
104         scanf("%d",&q[i]);
105         for(int j=1;j<=p;++j)
106             scanf("%d",&in[i][j]);
107         for(int j=1;j<=p;++j)
108             scanf("%d",&out[i][j]);
109     }
110     for(int i=1;i<=n;++i)
111         addedge(i,n+i,q[i]);
112     for(int i=1;i<=n;++i)
113         for(int j=1;j<=n;++j)
114             if(i!=j)
115             {
116                 bool flag=true;
117                 for(int k=1;k<=p;++k)
118                 {
119                     if(out[i][k]==0&&in[j][k]==1)
120                     {
121                         flag=false;
122                         break;
123                     }
124                     if(out[i][k]==1&&in[j][k]==0)
125                     {
126                         flag=false;
127                         break;
128                     }
129                 }
130                 if(flag)
131                     addedge(i+n,j,min(q[i],q[j]));
132             }
133     for(int i=1;i<=n;++i)
134     {
135         bool f=true;
136         for(int j=1;j<=p;++j)
137         {
138             if(in[i][j]==1)
139             {
140                 f=false;
141                 break;
142             }
143         }
144         if(f)    addedge(0,i,q[i]);
145     }
146     for(int i=1;i<=n;++i)
147     {
148         bool f=true;
149         for(int j=1;j<=p;++j)
150         {
151             if(out[i][j]==0)
152             {
153                 f=false;
154                 break;
155             }
156         }
157         if(f) 
158             addedge(i+n,2*n+1,q[i]);
159     }
160     int res=dinic(0,2*n+1,2*n+2);
161     int count=0;
162     for(int i=1;i<=n;++i)
163         for(int j=head[i+n];j!=-1;j=edge[j].next)
164             if(edge[j].to!=2*n+1&&edge[j].flow>0)
165                 count++;
166     cout<<res<<" "<<count<<endl;
167     for(int i=1;i<=n;++i)
168         for(int j=head[i+n];j!=-1;j=edge[j].next)
169             if(edge[j].to!=2*n+1&&edge[j].flow>0)
170                 cout<<i<<" "<<edge[j].to<<" "<<edge[j].flow<<endl;
171     return 0;
172 }
View Code

 

B.  poj3281     Dining

建图方法:为使每一头牛都对应每一份食物与饮料,需要将每头牛拆点,一共有2*n+f+d+2个顶点,0表示源点,2*n+f+d+1表示汇点,由源点指向食物,再由食物指向牛,牛指向自己的对应点,再指向对应的饮料,饮料再指向汇点。全部是有向的边,而且权值全部为1,1到f为食物点,f+1到f+2*n为牛点,f+2*n+1到f+2*n+d为饮料点。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<cstring>
  5 
  6 using namespace std;
  7 const int MAXN = 500;
  8 const int MAXM = 500*500;
  9 const int INF = 0x3f3f3f3f;
 10 struct Edge 
 11 {
 12     int to, next, cap, flow;
 13 }edge[MAXM];
 14 int tol;
 15 int head[MAXN];
 16 int gap[MAXN], dep[MAXN], cur[MAXN];
 17 void init() 
 18 {
 19     tol = 0;
 20     memset(head, -1, sizeof(head));
 21 }
 22 void addedge(int u, int v, int w, int rw = 0) 
 23 {
 24     edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0;
 25     edge[tol].next = head[u]; head[u] = tol++;
 26     edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0;
 27     edge[tol].next = head[v]; head[v] = tol++;
 28 }
 29 int Q[MAXN];
 30 void BFS(int start, int end) 
 31 {
 32     memset(dep, -1, sizeof(dep));
 33     memset(gap, 0, sizeof(gap));
 34     gap[0] = 1;
 35     int front = 0, rear = 0;
 36     dep[end] = 0;
 37     Q[rear++] = end;
 38     while(front != end) {
 39         int u = Q[front++];
 40         for(int i = head[u]; i != -1; i = edge[i].next) {
 41             int v = edge[i].to;
 42             if(dep[v] != -1) continue;
 43             Q[rear++] = v;
 44             dep[v] = dep[u] + 1;
 45             gap[dep[v]]++;
 46         }
 47     }
 48 }
 49 int S[MAXN];
 50 int sap(int start, int end, int N) {
 51     BFS(start, end);
 52     memcpy(cur, head, sizeof(head));
 53     int top = 0;
 54     int u = start;
 55     int ans = 0;
 56     while(dep[start] < N) 
 57     {
 58         if(u == end) 
 59         {
 60             int Min = INF;
 61             int inser;
 62             for(int i = 0; i < top; i++)
 63                 if(Min > edge[S[i]].cap - edge[S[i]].flow) {
 64                     Min = edge[S[i]].cap - edge[S[i]].flow;
 65                     inser = i;
 66                 }
 67             for(int i = 0; i < top; i++) 
 68             {
 69                 edge[S[i]].flow += Min;
 70                 edge[S[i]^1].flow -= Min;
 71             }
 72             ans += Min;
 73             top = inser;
 74             u = edge[S[top]^1].to;
 75             continue;
 76         }
 77         bool flag = false;
 78         int v;
 79         for(int i = cur[u]; i != -1; i = edge[i].next) 
 80         {
 81             v = edge[i].to;
 82             if(edge[i].cap - edge[i].flow && dep[v] + 1 == dep[u])                 {
 83                 flag = true;
 84                 cur[u] = i;
 85                 break;
 86             }
 87         }
 88         if(flag) 
 89         {
 90             S[top++] = cur[u];
 91             u = v;
 92             continue;
 93         }
 94         int Min = N;
 95         for(int i = head[u]; i != -1; i = edge[i].next)
 96             if(edge[i].cap - edge[i].flow && dep[edge[i].to] < Min) 
 97             {
 98                 Min = dep[edge[i].to];
 99                 cur[u] = i;
100             }
101         gap[dep[u]]--;
102         if(!gap[dep[u]]) return ans;
103         dep[u] = Min + 1;
104         gap[dep[u]]++;
105         if(u != start) u = edge[S[--top]^1].to;
106     }
107     return ans;
108 }
109 
110 int f,n,d;
111 int main()
112 {
113     scanf("%d%d%d",&n,&f,&d);
114     init();
115     for(int i=1;i<=n;++i)
116     {
117         int a,b,num;
118         scanf("%d%d",&a,&b);
119         for(int j=1;j<=a;++j)
120         {
121             scanf("%d",&num);
122             addedge(num,i+f,1);
123         }
124         for(int j=1;j<=b;++j)
125         {
126             scanf("%d",&num);
127             addedge(i+f+n,f+2*n+num,1);
128         }
129         addedge(f+i,f+n+i,1);
130     }
131     for(int i=1;i<=f;++i)
132         addedge(0,i,1);
133     for(int i=1;i<=d;++i)
134         addedge(f+2*n+i,f+2*n+d+1,1);
135     int res=sap(0,f+2*n+d+1,f+2*n+d+2);
136     cout<<res<<endl;
137     return 0;
138 }
View Code

 

C.   poj1087    A Plug for UNIX

题目大意:这题题目意思实在太难懂,不过题目意思搞清楚之后还是比较好做的。

题目中有三种物品:插座,电器和转换器。

首先有n种插座,n种插座用字符串表示,这n种插座可以理解为是插在电源上的插座。
然后有m个电器,现在电器要充电,电器用字符串表示,每个电器都有自己需要插的插座
(这个插座可以不是那n个插在电源上的插座,可以是其他的插座)。
最后有k种转换器:s1 s2代表这个转换器可以将s1插座转换成s2插座,这些s1与s2也可以不是那n个插在电源上的插座。

给出这些个信息问你还有多少个电器没有插座可以用。

建图方法:
建一个源点,指向所有电器,容量为1。所有电器指向他们可以插的那个插头上,容量为1。
如果一个插头可以转换另一个插头,那么将s1指向s2,容量为无限大,将所有插在电源上的插头指向汇点,容量为1。

最后求源点到汇点的最大流即可,不过建图会比较复杂,因为涉及到字符串的处理,所以用map容器存储结点编号比较好做点。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<queue>
  6 #include<map>
  7 #include<string>
  8 
  9 using namespace std;
 10 const int MAXN = 1010;
 11 const int MAXM = 1000020;
 12 const int INF = 0x3f3f3f3f;
 13 struct Edge 
 14 {
 15     int to, next, cap, flow;
 16 }edge[MAXM];
 17 int tol;
 18 int head[MAXN];
 19 void init() 
 20 {
 21     tol = 2;
 22     memset(head, -1, sizeof(head));
 23 }
 24 void addedge(int u, int v, int w, int rw=0) 
 25 {
 26     edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0;
 27     edge[tol].next = head[u]; head[u] = tol++;
 28     edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0;
 29     edge[tol].next = head[v]; head[v] = tol++;
 30 }
 31 int Q[MAXN];
 32 int dep[MAXN], cur[MAXN], sta[MAXN];
 33 bool bfs(int s, int t, int n) 
 34 {
 35     int front = 0, tail = 0;
 36     memset(dep, -1, sizeof(dep[0])*(n+1));
 37     dep[s] = 0;
 38     Q[tail++] = s;
 39     while(front < tail)
 40     {
 41         int u = Q[front++];
 42         for(int i = head[u]; i != -1; i = edge[i].next) 
 43         {
 44             int v = edge[i].to;
 45             if(edge[i].cap > edge[i].flow && dep[v] == -1)                 {
 46                 dep[v] = dep[u] + 1;
 47                 if(v == t) return true;
 48                 Q[tail++] = v;
 49             }
 50         }
 51     }
 52     return false;
 53 }
 54 int dinic(int s, int t, int n) {
 55     int maxflow = 0;
 56     while(bfs(s, t, n)) {
 57         for(int i = 0; i < n; i++) cur[i] = head[i];
 58         int u = s, tail = 0;
 59         while(cur[s] != -1)
 60         {
 61             if(u == t) 
 62             {
 63                 int tp = INF;
 64                 for(int i = tail-1; i >= 0; i--)
 65                     tp = min(tp, edge[sta[i]].cap-edge[sta[i]].flow);
 66                 maxflow+=tp;
 67                 for(int i = tail-1; i >= 0; i--) {
 68                     edge[sta[i]].flow+=tp;
 69                     edge[sta[i]^1].flow-=tp;
 70                     if(edge[sta[i]].cap-edge[sta[i]].flow==0)
 71                         tail = i;
 72                 }
 73                 u = edge[sta[tail]^1].to;
 74             }
 75             else 
 76                 if(cur[u] != -1 && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] + 1 == dep[edge[cur[u]].to]) 
 77                 {
 78                     sta[tail++] = cur[u];
 79                     u = edge[cur[u]].to;
 80                 }
 81                 else 
 82                 {
 83                     while(u != s && cur[u] == -1)
 84                         u = edge[sta[--tail]^1].to;
 85                     cur[u] = edge[cur[u]].next;
 86                 }
 87         }
 88     }
 89     return maxflow;
 90 }
 91 
 92 map<string,int> m1,m2;
 93 int n,m,k;
 94 
 95 int main()
 96 {
 97     m1.clear();
 98     m2.clear();
 99     init();
100     scanf("%d",&n);
101     for(int i=1;i<=n;++i)
102     {
103         string s;
104         cin>>s;
105         m1[s]=i;
106         addedge(0,i,1);
107     }
108     scanf("%d",&m);
109     int cnt=n;
110     for(int i=1;i<=m;++i)
111     {
112         string s1,s2;
113         cin>>s1>>s2;
114         m2[s1]=i+300;
115         if(m1[s2]==0)
116             m1[s2]=++cnt;
117         addedge(m1[s2],m2[s1],1);
118         addedge(m2[s1],400,1);
119     }
120     scanf("%d",&k);
121     string a1[MAXN],a2[MAXN];
122     for(int i=1;i<=k;++i)
123         cin>>a1[i]>>a2[i];
124     for(int i=1;i<=k;++i)
125     {
126         if(m1[a1[i]]==0)
127             m1[a1[i]]=++cnt;
128         if(m1[a2[i]]==0)
129             m1[a2[i]]=++cnt;
130         addedge(m1[a2[i]],m1[a1[i]],INF);
131     }
132     int res=dinic(0,400,401);
133 //    cout<<m<<"   "<<res<<endl;
134     cout<<m-res<<endl;
135     return 0;
136 }
View Code

 

 D.   poj2195      Going Home

题意:有若干个人和若干个房子在一个给定网格中,每人走一个都要一定花费,每个房子只能容纳一人,现要求让所有人进入房子,且总花费最小。
分析:简单题,题目中关键字为:每房子容纳一人,行走有花费,典型的最小费用最大流问题。建图加入超级终点和源点,注意对所有房子和人之间建立边。最后求最小费用最大流即可。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<queue>
  6 
  7 using namespace std;
  8 const int MAXN = 10000;
  9 const int MAXM = 100000;
 10 const int INF = 0x3f3f3f3f;
 11 struct Edge 
 12 {
 13     int to, next, cap, flow, cost;
 14 }edge[MAXM];
 15 int head[MAXN], tol;
 16 int pre[MAXN], dis[MAXN];
 17 bool vis[MAXN];
 18 int N;
 19 void init(int n) 
 20 {
 21     N = n;
 22     tol = 0;
 23     memset(head, -1, sizeof(head));
 24 }
 25 void addedge(int u, int v, int cap, int cost) 
 26 {
 27     edge[tol].to = v; edge[tol].cap = cap;
 28     edge[tol].cost = cost; edge[tol].flow = 0;
 29     edge[tol].next = head[u]; head[u] = tol++;
 30     edge[tol].to = u; edge[tol].cap = 0;
 31     edge[tol].cost = -cost; edge[tol].flow = 0;
 32     edge[tol].next = head[v]; head[v] = tol++;
 33 }
 34 bool spfa(int s, int t) 
 35 {
 36     queue<int> q;
 37     for(int i = 0; i < N; i++) 
 38     {
 39         dis[i] = INF;
 40         vis[i] = false;
 41         pre[i] = -1;
 42     }
 43     dis[s] = 0; vis[s] = true;
 44     q.push(s);
 45     while(!q.empty()) 
 46     {
 47         int u = q.front();
 48         q.pop();
 49         vis[u] = false;
 50         for(int i = head[u]; i != -1; i = edge[i].next)
 51         { 
 52             int v = edge[i].to;
 53             if(edge[i].cap > edge[i].flow && dis[v] > dis[u] + edge[i].cost) 
 54             {
 55                 dis[v] = dis[u] + edge[i].cost;
 56                 pre[v] = i;
 57                 if(!vis[v]) 
 58                 {
 59                     vis[v] = true;
 60                     q.push(v);
 61                 }
 62             }
 63         }
 64     }
 65     if(pre[t] == -1) return false;
 66     else return true;
 67 }
 68 
 69 int minCostMaxflow(int s, int t, int &cost) 
 70 {
 71     int flow = 0;
 72     cost = 0;
 73     while(spfa(s, t))
 74     {
 75         int Min = INF;
 76         for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]) 
 77         {
 78             if(Min > edge[i].cap - edge[i].flow)
 79                 Min = edge[i].cap - edge[i].flow;
 80         }
 81         for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]) 
 82         {
 83             edge[i].flow += Min;
 84             edge[i^1].flow -= Min;
 85             cost += edge[i].cost * Min;
 86         }
 87         flow += Min;
 88     }
 89     return flow;
 90 }
 91 
 92 int n,m;
 93 char map[MAXN][MAXN];
 94 struct House
 95 {
 96     int x,y;
 97 }house[MAXN];
 98 
 99 struct Man
100 {
101     int x,y;
102 }man[MAXN];
103 
104 int dist(int i,int j)
105 {
106     return abs(man[i].x-house[j].x)+abs(man[i].y-house[j].y);
107 }
108 
109 int main()
110 {
111     while(~scanf("%d%d",&n,&m)&&(n||m))
112     {
113         for(int i=0;i<n;++i)
114             scanf("%s",map[i]);
115         int mnum=0,hnum=0;
116         int count=0;
117         for(int i=0;i<n;++i)
118             for(int j=0;j<m;++j)
119             {
120                 if(map[i][j]=='m')
121                 {
122                     count++;
123                     mnum++;
124                     man[mnum].x=i+1;
125                     man[mnum].y=j+1;
126                 }
127                 if(map[i][j]=='H')
128                 {
129                     hnum++;
130                     house[hnum].x=i+1;
131                     house[hnum].y=j+1;
132                 }
133             }
134         init(2*count+2);
135     //    cout<<count<<endl;
136         for(int i=1;i<=count;++i)
137             for(int j=1;j<=count;++j)
138                 addedge(i,j+count,1,dist(i,j));
139         for(int i=1;i<=count;++i)
140         {
141             addedge(0,i,1,0);
142             addedge(i+count,2*count+1,1,0);
143         }
144         int cost;
145         minCostMaxflow(0,2*count+1,cost);
146         cout<<cost<<endl;
147     }
148     return 0;
149 }
View Code

 

E.    poj2516     Minimum Cost

分析:由于每种物品之间是独立的,所以可以将k种物品分开求最小费用再相加,即对每一种物品建一幅图。可以在建图前先判断是否需求全部能满足。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<queue>
  6 
  7 using namespace std;
  8 const int MAXN = 200;
  9 const int MAXM = 40000;
 10 const int INF = 0x3f3f3f3f;
 11 struct Edge 
 12 {
 13     int to, next, cap, flow, cost;
 14 }edge[MAXM];
 15 int head[MAXN], tol;
 16 int pre[MAXN], dis[MAXN];
 17 bool vis[MAXN];
 18 int N;
 19 void init(int n) 
 20 {
 21     N = n;
 22     tol = 0;
 23     memset(head, -1, sizeof(head));
 24 }
 25 void addedge(int u, int v, int cap, int cost) 
 26 {
 27     edge[tol].to = v; edge[tol].cap = cap;
 28     edge[tol].cost = cost; edge[tol].flow = 0;
 29     edge[tol].next = head[u]; head[u] = tol++;
 30     edge[tol].to = u; edge[tol].cap = 0;
 31     edge[tol].cost = -cost; edge[tol].flow = 0;
 32     edge[tol].next = head[v]; head[v] = tol++;
 33 }
 34 bool spfa(int s, int t) 
 35 {
 36     queue<int> q;
 37     for(int i = 0; i < N; i++) 
 38     {
 39         dis[i] = INF;
 40         vis[i] = false;
 41         pre[i] = -1;
 42     }
 43     dis[s] = 0; vis[s] = true;
 44     q.push(s);
 45     while(!q.empty()) 
 46     {
 47         int u = q.front();
 48         q.pop();
 49         vis[u] = false;
 50         for(int i = head[u]; i != -1; i = edge[i].next)
 51         { 
 52             int v = edge[i].to;
 53             if(edge[i].cap > edge[i].flow && dis[v] > dis[u] + edge[i].cost) 
 54             {
 55                 dis[v] = dis[u] + edge[i].cost;
 56                 pre[v] = i;
 57                 if(!vis[v]) 
 58                 {
 59                     vis[v] = true;
 60                     q.push(v);
 61                 }
 62             }
 63         }
 64     }
 65     if(pre[t] == -1) return false;
 66     else return true;
 67 }
 68 
 69 int minCostMaxflow(int s, int t, int &cost) 
 70 {
 71     int flow = 0;
 72     cost = 0;
 73     while(spfa(s, t))
 74     {
 75         int Min = INF;
 76         for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]) 
 77         {
 78             if(Min > edge[i].cap - edge[i].flow)
 79                 Min = edge[i].cap - edge[i].flow;
 80         }
 81         for(int i = pre[t]; i != -1; i = pre[edge[i^1].to]) 
 82         {
 83             edge[i].flow += Min;
 84             edge[i^1].flow -= Min;
 85             cost += edge[i].cost * Min;
 86         }
 87         flow += Min;
 88     }
 89     return flow;
 90 }
 91 
 92 int n,m,k;
 93 int need[60][60],supply[60][60],cost[60][60],sumneed[60],sumsupply[60];
 94 int main()
 95 {
 96     while(scanf("%d%d%d",&n,&m,&k))
 97     {
 98         if(n==0 && m==0 && k==0)
 99             break;
100         memset(sumneed,0,sizeof(sumneed));
101         memset(sumsupply,0,sizeof(sumsupply));
102         for(int i=1;i<=n;++i)
103             for(int j=1;j<=k;++j)
104             {
105                 scanf("%d",&need[i][j]);
106                 sumneed[j]+=need[i][j];
107             }
108         for(int i=1;i<=m;++i)
109             for(int j=1;j<=k;++j)
110             {
111                 scanf("%d",&supply[i][j]);
112                 sumsupply[j]+=supply[i][j];
113             }
114         bool flag=true;
115         for(int i=1;i<=k;++i)
116         {
117             if(sumsupply[i]<sumneed[i])
118             {
119                 flag=false;
120                 break;
121             }
122         }
123         int res=0;
124         for(int l=1;l<=k;++l)
125         {
126             init(m+n+2);
127             for(int i=1;i<=n;++i)
128                 for(int j=1;j<=m;++j)
129                     scanf("%d",&cost[i][j]);
130             for(int i=1;i<=m;++i)
131                 for(int j=1;j<=n;++j)
132                     addedge(i,j+m,need[j][l],cost[j][i]);
133             for(int i=1;i<=m;++i)
134                 addedge(0,i,supply[i][l],0);
135             for(int i=1;i<=n;++i)
136                 addedge(i+m,m+n+1,need[i][l],0);
137             int ans;
138             minCostMaxflow(0,m+n+1,ans);
139             res+=ans;
140         }
141         if(!flag)
142             cout<<-1<<endl;
143         else
144             cout<<res<<endl;
145     }
146     return 0;
147 }
View Code

 

F.    poj1459     Power Network

分析:题意比较烦,整理清楚就知道是裸的最大流,需要增加一个超级源点和超级汇点,把所给的发电站都和超级源点相连,把所给的消耗站都和超级汇点相连,最后跑一遍最大流即可。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<queue>
  6 
  7 using namespace std;
  8 const int MAXN = 1200;
  9 const int MAXM = 120*1200;
 10 const int INF = 0x3f3f3f3f;
 11 struct Edge 
 12 {
 13     int to, next, cap, flow;
 14 }edge[MAXM];
 15 int tol;
 16 int head[MAXN];
 17 void init() 
 18 {
 19     tol = 2;
 20     memset(head, -1, sizeof(head));
 21 }
 22 void addedge(int u, int v, int w, int rw=0) 
 23 {
 24     edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0;
 25     edge[tol].next = head[u]; head[u] = tol++;
 26     edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0;
 27     edge[tol].next = head[v]; head[v] = tol++;
 28 }
 29 int Q[MAXN];
 30 int dep[MAXN], cur[MAXN], sta[MAXN];
 31 bool bfs(int s, int t, int n) 
 32 {
 33     int front = 0, tail = 0;
 34     memset(dep, -1, sizeof(dep[0])*(n+1));
 35     dep[s] = 0;
 36     Q[tail++] = s;
 37     while(front < tail)
 38     {
 39         int u = Q[front++];
 40         for(int i = head[u]; i != -1; i = edge[i].next) 
 41         {
 42             int v = edge[i].to;
 43             if(edge[i].cap > edge[i].flow && dep[v] == -1)                 {
 44                 dep[v] = dep[u] + 1;
 45                 if(v == t) return true;
 46                 Q[tail++] = v;
 47             }
 48         }
 49     }
 50     return false;
 51 }
 52 int dinic(int s, int t, int n) {
 53     int maxflow = 0;
 54     while(bfs(s, t, n)) {
 55         for(int i = 0; i < n; i++) cur[i] = head[i];
 56         int u = s, tail = 0;
 57         while(cur[s] != -1)
 58         {
 59             if(u == t) 
 60             {
 61                 int tp = INF;
 62                 for(int i = tail-1; i >= 0; i--)
 63                     tp = min(tp, edge[sta[i]].cap-edge[sta[i]].flow);
 64                 maxflow+=tp;
 65                 for(int i = tail-1; i >= 0; i--) {
 66                     edge[sta[i]].flow+=tp;
 67                     edge[sta[i]^1].flow-=tp;
 68                     if(edge[sta[i]].cap-edge[sta[i]].flow==0)
 69                         tail = i;
 70                 }
 71                 u = edge[sta[tail]^1].to;
 72             }
 73             else 
 74                 if(cur[u] != -1 && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] + 1 == dep[edge[cur[u]].to]) 
 75                 {
 76                     sta[tail++] = cur[u];
 77                     u = edge[cur[u]].to;
 78                 }
 79                 else 
 80                 {
 81                     while(u != s && cur[u] == -1)
 82                         u = edge[sta[--tail]^1].to;
 83                     cur[u] = edge[cur[u]].next;
 84                 }
 85         }
 86     }
 87     return maxflow;
 88 }
 89 int n,np,nc,m;
 90 char s[30];
 91 int u,v,z;
 92 int main()
 93 {
 94     while(~scanf("%d%d%d%d",&n,&np,&nc,&m))
 95     {
 96         init();
 97         for(int i=1;i<=m;++i)
 98         {
 99             scanf("%s",s);
100             sscanf(s,"(%d,%d)%d",&u,&v,&z);
101             addedge(u+1,v+1,z);
102         }
103         for(int i=1;i<=np;++i)
104         {
105             scanf("%s",s);
106             sscanf(s,"(%d)%d",&u,&z);
107             addedge(0,u+1,z);
108         }
109         for(int i=1;i<=nc;++i)
110         {
111             scanf("%s",s);
112             sscanf(s,"(%d)%d",&u,&z);
113             addedge(u+1,n+2,z);
114         }
115         cout<<dinic(0,n+2,n+3)<<endl;
116     }
117     return 0;
118 }
View Code

 

G.    hdu4280     Island Transport

分析:裸的最大流,但是由于边数比较多,容易超时和爆栈,我本来是存双向边的,T了好几发,修改了存边方式9000+ms水过。。。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<cstring>
  5 
  6 using namespace std;
  7 const int MAXN = 100010;
  8 const int MAXM = 1200012;
  9 const int INF = 0x3f3f3f3f;
 10 struct Edge 
 11 {
 12     int from,to, next, cap, flow;
 13 }edge[MAXM];
 14 int tol;
 15 int head[MAXN];
 16 void init() 
 17 {
 18     tol = 2;
 19     memset(head, -1, sizeof(head));
 20 }
 21 int min(int a,int b)
 22 {
 23 return a>b?b:a;
 24 }
 25 void addedge(int u, int v, int w, int rw=0) 
 26 {
 27         edge[tol].from=u;
 28     edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0;
 29     edge[tol].next = head[u]; head[u] = tol++;
 30 }
 31 int Q[MAXN];
 32 int dep[MAXN], cur[MAXN], sta[MAXN];
 33 bool bfs(int s, int t, int n) 
 34 {
 35     int front = 0, tail = 0;
 36     memset(dep, -1, sizeof(dep[0])*(n+1));
 37     dep[s] = 0;
 38     Q[tail++] = s;
 39     while(front < tail)
 40     {
 41         int u = Q[front++];
 42         for(int i = head[u]; i != -1; i = edge[i].next) 
 43         {
 44             int v = edge[i].to;
 45             if(edge[i].cap > edge[i].flow && dep[v] == -1)                 {
 46                 dep[v] = dep[u] + 1;
 47                 if(v == t) return true;
 48                 Q[tail++] = v;
 49             }
 50         }
 51     }
 52     return false;
 53 }
 54 int dinic(int s, int t, int n) {
 55     int maxflow = 0;
 56     while(bfs(s, t, n)) {
 57         for(int i = 0; i < n; i++) cur[i] = head[i];
 58         int u = s, tail = 0;
 59         while(cur[s] != -1)
 60         {
 61             if(u == t) 
 62             {
 63                 int tp = INF;
 64                 for(int i = tail-1; i >= 0; i--)
 65                     tp = min(tp, edge[sta[i]].cap-edge[sta[i]].flow);
 66                 maxflow+=tp;
 67                 for(int i = tail-1; i >= 0; i--) {
 68                     edge[sta[i]].flow+=tp;
 69                     edge[sta[i]^1].flow-=tp;
 70                     if(edge[sta[i]].cap-edge[sta[i]].flow==0)
 71                         tail = i;
 72                 }
 73                 u = edge[sta[tail]].from;
 74             }
 75             else 
 76                 if(cur[u] != -1 && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] + 1 == dep[edge[cur[u]].to]) 
 77                 {
 78                     sta[tail++] = cur[u];
 79                     u = edge[cur[u]].to;
 80                 }
 81                 else 
 82                 {
 83                     while(u != s && cur[u] == -1)
 84                         u = edge[sta[--tail]].from;
 85                     cur[u] = edge[cur[u]].next;
 86                 }
 87         }
 88     }
 89     return maxflow;
 90 }
 91 int n,m;
 92 struct Node
 93 {
 94     int x,y;
 95 }node[MAXN];
 96 
 97 int main()
 98 {
 99     int t;
100     scanf("%d",&t);
101     while(t--)
102     {
103         scanf("%d%d",&n,&m);
104         Node a,b;
105         init();
106         int num1,num2;
107         a.x=INF;
108         b.x=-INF;
109         for(int i=1;i<=n;++i)
110         {
111             int x,y;
112             scanf("%d%d",&x,&y);
113             if(x<a.x)
114             {
115                 a.x=x;
116                 num1=i-1;
117             }
118             if(x>b.x)
119             {
120                 b.x=x;
121                 num2=i-1;
122             }
123         }
124         for(int i=1;i<=m;++i)
125         {
126             int u,v,c;
127             scanf("%d%d%d",&u,&v,&c);
128             addedge(u-1,v-1,c);
129             addedge(v-1,u-1,c);
130         }
131         cout<<dinic(num1,num2,n)<<endl;
132     }
133     return 0;
134 }
135     
View Code

 

H.    hdu4292      Food

分析:为了控制一个人只连一瓶饮料,一份食物,那么我们可以把一个人拆成两个,他们之间连一条权值为1的边,另外左边连它喜欢的食物,权值为1,右边连它喜欢的饮料,权值为1,在源点连食物的时候加流量限制,汇点加流量限制,跑一遍最大流即可。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<cstring>
  5 
  6 using namespace std;
  7 const int INF = 0x3f3f3f3f;
  8 const int MAXN = 1000;
  9 const int MAXM = 9000000;
 10 struct Edge 
 11 {
 12     int to, next, cap, flow;
 13 }edge[MAXM];
 14 int tol;
 15 int head[MAXN];
 16 void init() 
 17 {
 18     tol = 2;
 19     memset(head, -1, sizeof(head));
 20 }
 21 void addedge(int u, int v, int w, int rw=0) 
 22 {
 23     edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0;
 24     edge[tol].next = head[u]; head[u] = tol++;
 25     edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0;
 26     edge[tol].next = head[v]; head[v] = tol++;
 27 }
 28 int Q[MAXN];
 29 int dep[MAXN], cur[MAXN], sta[MAXN];
 30 bool bfs(int s, int t, int n) 
 31 {
 32     int front = 0, tail = 0;
 33     memset(dep, -1, sizeof(dep[0])*(n+1));
 34     dep[s] = 0;
 35     Q[tail++] = s;
 36     while(front < tail)
 37     {
 38         int u = Q[front++];
 39         for(int i = head[u]; i != -1; i = edge[i].next) 
 40         {
 41             int v = edge[i].to;
 42             if(edge[i].cap > edge[i].flow && dep[v] == -1)                         {
 43                 dep[v] = dep[u] + 1;
 44                 if(v == t) return true;
 45                 Q[tail++] = v;
 46             }
 47         }
 48     }
 49     return false;
 50 }
 51 int dinic(int s, int t, int n) {
 52     int maxflow = 0;
 53     while(bfs(s, t, n)) {
 54         for(int i = 0; i < n; i++) cur[i] = head[i];
 55         int u = s, tail = 0;
 56         while(cur[s] != -1)
 57         {
 58             if(u == t) 
 59             {
 60                 int tp = INF;
 61                 for(int i = tail-1; i >= 0; i--)
 62                     tp = min(tp, edge[sta[i]].cap-edge[sta[i]].flow);
 63                 maxflow+=tp;
 64                 for(int i = tail-1; i >= 0; i--) {
 65                     edge[sta[i]].flow+=tp;
 66                     edge[sta[i]^1].flow-=tp;
 67                     if(edge[sta[i]].cap-edge[sta[i]].flow==0)
 68                         tail = i;
 69                 }
 70                 u = edge[sta[tail]^1].to;
 71             }
 72             else 
 73                 if(cur[u] != -1 && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] + 1 == dep[edge[cur[u]].to]) 
 74                 {
 75                     sta[tail++] = cur[u];
 76                     u = edge[cur[u]].to;
 77                 }
 78                 else 
 79                 {
 80                     while(u != s && cur[u] == -1)
 81                         u = edge[sta[--tail]^1].to;
 82                     cur[u] = edge[cur[u]].next;
 83                 }
 84         }
 85     }
 86     return maxflow;
 87 }
 88 int num,n,f,d;
 89 char s[MAXN];
 90 
 91 int main()
 92 {
 93     while(~scanf("%d%d%d",&n,&f,&d))
 94     {
 95         init();
 96         for(int i=1;i<=f;++i)
 97         {
 98             scanf("%d",&num);
 99             addedge(0,i,num);
100         }
101         for(int i=1;i<=d;++i)
102         {
103             scanf("%d",&num);
104             addedge(f+2*n+i,f+2*n+d+1,num);
105         }
106         for(int i=1;i<=n;++i)
107         {
108             addedge(f+i,f+n+i,1);
109             scanf("%s",s);
110             for(int j=1;j<=f;++j)
111                 if(s[j-1]=='Y')
112                     addedge(j,i+f,1);
113         }
114         for(int i=1;i<=n;++i)
115         {
116             scanf("%s",s);
117             for(int j=1;j<=d;++j)
118                 if(s[j-1]=='Y')
119                     addedge(i+f+n,f+2*n+j,1);
120         }
121         cout<<dinic(0,f+2*n+d+1,f+2*n+d+2)<<endl;
122     }
123     return 0;
124 }
View Code

 

I.     hdu4289    Control

题意:给出一个由n个点,m条边组成的无向图。给出两个点s,t。对于图中的每个点,去掉这个点都需要一定的花费。求至少多少花费才能使得s和t之间不连通。

分析:题意即求最小割,将每个点拆点,点与对应点的边权为去掉该点的花费,原图中所有边的边权赋为无穷大,跑一遍最大流即可。(最大流即最小割)

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<cstring>
  5 
  6 using namespace std;
  7 const int MAXN = 2010;
  8 const int MAXM = 1200012;
  9 const int INF = 0x3f3f3f3f;
 10 struct Edge 
 11 {
 12     int to, next, cap, flow;
 13 }edge[MAXM];
 14 int tol;
 15 int head[MAXN];
 16 void init() 
 17 {
 18     tol = 2;
 19     memset(head, -1, sizeof(head));
 20 }
 21 void addedge(int u, int v, int w, int rw=0) 
 22 {
 23     edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0;
 24     edge[tol].next = head[u]; head[u] = tol++;
 25     edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0;
 26     edge[tol].next = head[v]; head[v] = tol++;
 27 }
 28 int Q[MAXN];
 29 int dep[MAXN], cur[MAXN], sta[MAXN];
 30 bool bfs(int s, int t, int n) 
 31 {
 32     int front = 0, tail = 0;
 33     memset(dep, -1, sizeof(dep[0])*(n+1));
 34     dep[s] = 0;
 35     Q[tail++] = s;
 36     while(front < tail)
 37     {
 38         int u = Q[front++];
 39         for(int i = head[u]; i != -1; i = edge[i].next) 
 40         {
 41             int v = edge[i].to;
 42             if(edge[i].cap > edge[i].flow && dep[v] == -1)                 {
 43                 dep[v] = dep[u] + 1;
 44                 if(v == t) return true;
 45                 Q[tail++] = v;
 46             }
 47         }
 48     }
 49     return false;
 50 }
 51 int dinic(int s, int t, int n) {
 52     int maxflow = 0;
 53     while(bfs(s, t, n)) {
 54         for(int i = 0; i < n; i++) cur[i] = head[i];
 55         int u = s, tail = 0;
 56         while(cur[s] != -1)
 57         {
 58             if(u == t) 
 59             {
 60                 int tp = INF;
 61                 for(int i = tail-1; i >= 0; i--)
 62                     tp = min(tp, edge[sta[i]].cap-edge[sta[i]].flow);
 63                 maxflow+=tp;
 64                 for(int i = tail-1; i >= 0; i--) {
 65                     edge[sta[i]].flow+=tp;
 66                     edge[sta[i]^1].flow-=tp;
 67                     if(edge[sta[i]].cap-edge[sta[i]].flow==0)
 68                         tail = i;
 69                 }
 70                 u = edge[sta[tail]^1].to;
 71             }
 72             else 
 73                 if(cur[u] != -1 && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] + 1 == dep[edge[cur[u]].to]) 
 74                 {
 75                     sta[tail++] = cur[u];
 76                     u = edge[cur[u]].to;
 77                 }
 78                 else 
 79                 {
 80                     while(u != s && cur[u] == -1)
 81                         u = edge[sta[--tail]^1].to;
 82                     cur[u] = edge[cur[u]].next;
 83                 }
 84         }
 85     }
 86     return maxflow;
 87 }
 88 int n,m,s,d;
 89 
 90 int main()
 91 {
 92     while(~scanf("%d%d",&n,&m))
 93     {
 94         init();
 95         scanf("%d%d",&s,&d);
 96         int c;
 97         for(int i=0;i<n;++i)
 98         {
 99             scanf("%d",&c);
100             addedge(i,i+n,c);
101         }
102         for(int i=1;i<=m;++i)
103         {
104             int a,b;
105             scanf("%d%d",&a,&b);
106             addedge(a-1+n,b-1,INF);
107             addedge(b-1+n,a-1,INF);
108         }
109         cout<<dinic(s-1,d-1+n,2*n)<<endl;
110     }
111     return 0;
112 }
View Code

 

J.     UVA10480    Sabotage

题意:旧政府有一个很庞大的网络系统,可以很方便的指挥他的城市,起义军为了减少伤亡所以决定破坏他们的网络,使他们的首都(1号城市)和最大的城市(2号城市)不能联

系,不过破坏不同的网络所花费的代价是不同的,现在起义军想知道最少花费的代价是多少,输出需要破坏的线路。

分析:与 I 题一样,也是求最小割,只要算出最大流即可。不过题目要求输出最小割的边,这也是可以用网络流解决的,方法:求完最大流后,在残留网络中从源点 s 开始 dfs ,将能

到达的点标号( c - f >0 的边),最后遍历一遍边集,将起点被标记、终点未被标记的边输出。(注意这是无向图,边只用输出一遍,而在有向图中,条件应该改为起点标号、终点未标或起点未标、终点标号的边)。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<cstring>
  5 #include<algorithm>
  6 
  7 using namespace std;
  8 const int MAXN = 200;
  9 const int MAXM = 5000;
 10 const int INF = 0x3f3f3f3f;
 11 struct Edge 
 12 {
 13     int from,to, next, cap, flow;
 14 }edge[MAXM];
 15 int tol;
 16 int head[MAXN];
 17 void init() 
 18 {
 19     tol = 2;
 20     memset(head, -1, sizeof(head));
 21 }
 22 int min(int a,int b)
 23 {
 24     return a>b?b:a;
 25 }
 26 void addedge(int u, int v, int w, int rw=0) 
 27 {
 28     edge[tol].from=u;
 29     edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0;
 30     edge[tol].next = head[u]; head[u] = tol++;
 31 }
 32 int Q[MAXN];
 33 int dep[MAXN], cur[MAXN], sta[MAXN];
 34 bool bfs(int s, int t, int n) 
 35 {
 36     int front = 0, tail = 0;
 37     memset(dep, -1, sizeof(dep[0])*(n+1));
 38     dep[s] = 0;
 39     Q[tail++] = s;
 40     while(front < tail)
 41     {
 42         int u = Q[front++];
 43         for(int i = head[u]; i != -1; i = edge[i].next) 
 44         {
 45             int v = edge[i].to;
 46             if(edge[i].cap > edge[i].flow && dep[v] == -1)                         {
 47                 dep[v] = dep[u] + 1;
 48                 if(v == t) return true;
 49                 Q[tail++] = v;
 50             }
 51         }
 52     }
 53     return false;
 54 }
 55 int dinic(int s, int t, int n) {
 56     int maxflow = 0;
 57     while(bfs(s, t, n)) {
 58         for(int i = 0; i < n; i++) cur[i] = head[i];
 59         int u = s, tail = 0;
 60         while(cur[s] != -1)
 61         {
 62             if(u == t) 
 63             {
 64                 int tp = INF;
 65                 for(int i = tail-1; i >= 0; i--)
 66                     tp = min(tp, edge[sta[i]].cap-edge[sta[i]].flow);
 67                 maxflow+=tp;
 68                 for(int i = tail-1; i >= 0; i--) {
 69                     edge[sta[i]].flow+=tp;
 70                     edge[sta[i]^1].flow-=tp;
 71                     if(edge[sta[i]].cap-edge[sta[i]].flow==0)
 72                         tail = i;
 73                 }
 74                 u = edge[sta[tail]].from;
 75             }
 76             else 
 77                 if(cur[u] != -1 && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] + 1 == dep[edge[cur[u]].to]) 
 78                 {
 79                     sta[tail++] = cur[u];
 80                     u = edge[cur[u]].to;
 81                 }
 82                 else 
 83                 {
 84                     while(u != s && cur[u] == -1)
 85                         u = edge[sta[--tail]].from;
 86                     cur[u] = edge[cur[u]].next;
 87                 }
 88         }
 89     }
 90     return maxflow;
 91 }
 92 int n,m;
 93 bool vis[MAXN];
 94 
 95 void dfs(int u)
 96 {
 97     vis[u]=true;
 98     for(int i=head[u];i!=-1;i=edge[i].next)
 99     {
100         int v=edge[i].to;
101         if(edge[i].cap>edge[i].flow&&(!vis[v]))
102                 dfs(v);
103     }
104 }
105 
106 int main()
107 {
108     while(~scanf("%d%d",&n,&m)&&n&&m)
109     {
110         init();
111         for(int i=1;i<=m;++i)
112         {
113             int u,v,c;
114             scanf("%d%d%d",&u,&v,&c);
115             addedge(u-1,v-1,c);
116             addedge(v-1,u-1,c);
117         }
118         dinic(0,1,n);
119         memset(vis,false,sizeof(vis));
120         dfs(0);
121         for(int i=2;i<tol;i=i+2)
122         {
123             int u=edge[i].from;
124             int v=edge[i].to;
125             if(vis[u]!=vis[v])
126             {
127                 cout<<u+1<<" "<<v+1<<endl;
128             }
129         }
130         cout<<endl;
131     }
132     return 0;
133 }
View Code

 

K.     hdu2732     Leapin' Lizards

题意:给你一个网格,网格上的一些位置上有一只蜥蜴,所有蜥蜴的最大跳跃距离是d,如果一只蜥蜴能跳出网格边缘,那么它就安全了。且每个网格有一个最大跳出次数x,即最多有x只蜥蜴从这个网格跳出,这个网格就再也不能有蜥蜴进来了。问你最少有多少只蜥蜴跳不出网格。

分析:这是一道最大流。源点S编号0,网格的每个格子分成两个点i和i+n*m(n和m为网格的行和列数,i编号点是表示蜥蜴进来,而i+n*m编号的点是表示蜥蜴出去)。汇点t编号n*m*2+1。如果格子i上有蜥蜴,那么从s到i有边(s,i,1)。如果格子i能承受x次跳出,那么有边(i,i+n*m,x)。如果从格子i能直接跳出网格边界,那么有边(i+n*m,t,INF)。如果从格子i不能直接跳出网格,那么从i到离i距离<=d的网格j有边(i+n*m,j,INF),注意这里的距离是曼哈顿距离。最终我们求出的最大流就是能跳出网格的蜥蜴数。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<cstring>
  5 
  6 using namespace std;
  7 const int MAXN = 2010;
  8 const int MAXM = 1200012;
  9 const int INF = 0x3f3f3f3f;
 10 struct Edge 
 11 {
 12     int to, next, cap, flow;
 13 }edge[MAXM];
 14 int tol;
 15 int head[MAXN];
 16 void init() 
 17 {
 18     tol = 2;
 19     memset(head, -1, sizeof(head));
 20 }
 21 void addedge(int u, int v, int w, int rw=0) 
 22 {
 23     edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0;
 24     edge[tol].next = head[u]; head[u] = tol++;
 25     edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0;
 26     edge[tol].next = head[v]; head[v] = tol++;
 27 }
 28 int Q[MAXN];
 29 int dep[MAXN], cur[MAXN], sta[MAXN];
 30 bool bfs(int s, int t, int n) 
 31 {
 32     int front = 0, tail = 0;
 33     memset(dep, -1, sizeof(dep[0])*(n+1));
 34     dep[s] = 0;
 35     Q[tail++] = s;
 36     while(front < tail)
 37     {
 38         int u = Q[front++];
 39         for(int i = head[u]; i != -1; i = edge[i].next) 
 40         {
 41             int v = edge[i].to;
 42             if(edge[i].cap > edge[i].flow && dep[v] == -1)                 {
 43                 dep[v] = dep[u] + 1;
 44                 if(v == t) return true;
 45                 Q[tail++] = v;
 46             }
 47         }
 48     }
 49     return false;
 50 }
 51 int dinic(int s, int t, int n) {
 52     int maxflow = 0;
 53     while(bfs(s, t, n)) {
 54         for(int i = 0; i < n; i++) cur[i] = head[i];
 55         int u = s, tail = 0;
 56         while(cur[s] != -1)
 57         {
 58             if(u == t) 
 59             {
 60                 int tp = INF;
 61                 for(int i = tail-1; i >= 0; i--)
 62                     tp = min(tp, edge[sta[i]].cap-edge[sta[i]].flow);
 63                 maxflow+=tp;
 64                 for(int i = tail-1; i >= 0; i--) {
 65                     edge[sta[i]].flow+=tp;
 66                     edge[sta[i]^1].flow-=tp;
 67                     if(edge[sta[i]].cap-edge[sta[i]].flow==0)
 68                         tail = i;
 69                 }
 70                 u = edge[sta[tail]^1].to;
 71             }
 72             else 
 73                 if(cur[u] != -1 && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] + 1 == dep[edge[cur[u]].to]) 
 74                 {
 75                     sta[tail++] = cur[u];
 76                     u = edge[cur[u]].to;
 77                 }
 78                 else 
 79                 {
 80                     while(u != s && cur[u] == -1)
 81                         u = edge[sta[--tail]^1].to;
 82                     cur[u] = edge[cur[u]].next;
 83                 }
 84         }
 85     }
 86     return maxflow;
 87 }
 88 int t,n,d;
 89 char s[30];
 90 int map[30][30];
 91 
 92 int main()
 93 {
 94     int t;
 95     scanf("%d",&t);
 96     for(int k=1;k<=t;++k)
 97     {
 98         init();
 99         scanf("%d%d",&n,&d);
100         memset(map,0,sizeof(map));
101         scanf("%s",s);
102         int m=strlen(s);
103         for(int i=0;i<m;++i)
104             map[1][i+1]=s[i]-'0';
105         for(int i=2;i<=n;++i)
106         {
107             scanf("%s",s);
108             for(int j=1;j<=m;++j)
109                 map[i][j]=s[j-1]-'0';
110         }
111         int sum=0;
112         for(int i=1;i<=n;++i)
113         {
114             scanf("%s",s);
115             for(int j=1;j<=m;++j)
116                 if(s[j-1]=='L')
117                 {
118                     sum++;
119                     addedge(0,(i-1)*m+j,1);
120                 }
121         }
122         for(int i=1;i<=n;++i)
123             for(int j=1;j<=m;++j)
124             {
125                 int num=(i-1)*m+j;
126                 if(map[i][j]==0)
127                     continue;
128                 addedge(num,num+n*m,map[i][j]);
129                 if(i<=d||n-i<d||j<=d||m-j<d)
130                     addedge(num+n*m,2*n*m+1,INF);
131                 else
132                 {
133                     for(int a=1;a<=n;++a)
134                         for(int b=1;b<=m;++b)
135                         {
136                             int id=(a-1)*m+b;
137                             if(id==num)
138                                 continue;
139                             if(abs(i-a)+abs(j-b)<=d&&map[a][b]>0)
140                                 addedge(num+n*m,id,INF);
141                         }
142                 }
143             }
144         int ans=sum-dinic(0,2*n*m+1,2*n*m+2);
145         printf("Case #%d: ",k);
146         if(ans==0)
147             printf("no lizard was left behind.\n");
148         else
149         {
150             if(ans==1)
151                 printf("1 lizard was left behind.\n");
152             else
153                 printf("%d lizards were left behind.\n",ans);
154         }
155     }
156     return 0;
157 }
View Code

 

L.      hdu3338      Kakuro Extension

分析:这道题可以用网络流来做。以空白格为节点,假设流是从左流入,从上流出的,流入的容量为行和,流出来容量为列和,其余容量不变。求满足的最大流。由于流量有上下限限制,可以给每个数都减掉1,则填出来的数字范围为0—8, 就可以用单纯的网络流搞定了。求出来再加上就可以了。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<cstring>
  5 
  6 using namespace std;
  7 const int MAXN = 20100;
  8 const int MAXM = 1200012;
  9 const int INF = 0x3f3f3f3f;
 10 struct Edge 
 11 {
 12     int to, next, cap, flow;
 13 }edge[MAXM];
 14 int tol;
 15 int head[MAXN];
 16 void init() 
 17 {
 18     tol = 2;
 19     memset(head, -1, sizeof(head));
 20 }
 21 void addedge(int u, int v, int w, int rw=0) 
 22 {
 23     edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0;
 24     edge[tol].next = head[u]; head[u] = tol++;
 25     edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0;
 26     edge[tol].next = head[v]; head[v] = tol++;
 27 }
 28 int Q[MAXN];
 29 int dep[MAXN], cur[MAXN], sta[MAXN];
 30 bool bfs(int s, int t, int n) 
 31 {
 32     int front = 0, tail = 0;
 33     memset(dep, -1, sizeof(dep[0])*(n+1));
 34     dep[s] = 0;
 35     Q[tail++] = s;
 36     while(front < tail)
 37     {
 38         int u = Q[front++];
 39         for(int i = head[u]; i != -1; i = edge[i].next) 
 40         {
 41             int v = edge[i].to;
 42             if(edge[i].cap > edge[i].flow && dep[v] == -1)                         {
 43                 dep[v] = dep[u] + 1;
 44                 if(v == t) return true;
 45                 Q[tail++] = v;
 46             }
 47         }
 48     }
 49     return false;
 50 }
 51 int dinic(int s, int t, int n) {
 52     int maxflow = 0;
 53     while(bfs(s, t, n)) {
 54         for(int i = 0; i < n; i++) cur[i] = head[i];
 55         int u = s, tail = 0;
 56         while(cur[s] != -1)
 57         {
 58             if(u == t) 
 59             {
 60                 int tp = INF;
 61                 for(int i = tail-1; i >= 0; i--)
 62                     tp = min(tp, edge[sta[i]].cap-edge[sta[i]].flow);
 63                 maxflow+=tp;
 64                 for(int i = tail-1; i >= 0; i--) {
 65                     edge[sta[i]].flow+=tp;
 66                     edge[sta[i]^1].flow-=tp;
 67                     if(edge[sta[i]].cap-edge[sta[i]].flow==0)
 68                         tail = i;
 69                 }
 70                 u = edge[sta[tail]^1].to;
 71             }
 72             else 
 73                 if(cur[u] != -1 && edge[cur[u]].cap > edge[cur[u]].flow && dep[u] + 1 == dep[edge[cur[u]].to]) 
 74                 {
 75                     sta[tail++] = cur[u];
 76                     u = edge[cur[u]].to;
 77                 }
 78                 else 
 79                 {
 80                     while(u != s && cur[u] == -1)
 81                         u = edge[sta[--tail]^1].to;
 82                     cur[u] = edge[cur[u]].next;
 83                 }
 84         }
 85     }
 86     return maxflow;
 87 }
 88 struct node
 89 {
 90     int x,y;
 91     int tmp;
 92 }s[11000],t[11000];
 93 int n,m;
 94 int a,b;
 95 int num[120][120][3],f[120][120];
 96 char str[100];
 97 
 98 int main()
 99 {
100 while(~scanf("%d%d",&n,&m))
101 {
102     memset(num,0,sizeof(num));
103     a=b=0;
104     init();
105     for(int i=1;i<=n;++i)
106     {
107         for(int j=1;j<=m;++j)
108         {
109             scanf("%s",str);
110         //    int len=strlen(str);
111             if(str[0]=='.') 
112             {
113                 num[i][j][0]=-1;
114                 continue;
115             }
116             if(str[0]!='X')
117             {
118                 num[i][j][1]=(str[0]-'0')*100+(str[1]-'0')*10+str[2]-'0';
119                 s[a].x=i;
120                 s[a].y=j;
121                 s[a++].tmp=num[i][j][1];
122             }
123             if(str[4]!='X')
124             {
125                 num[i][j][2]=(str[4]-'0')*100+(str[5]-'0')*10+str[6]-'0';
126                 t[b].x=i;
127                 t[b].y=j;
128                 t[b++].tmp=num[i][j][2];
129             }
130         }
131     }
132 /*    for(int i=1;i<=n;++i)
133     {
134         for(int j=1;j<=m;++j)
135         {
136             cout<<num[i][j][0]<<"  "<<num[i][j][1]<<"  "<<num[i][j][2]<<"        ";
137         }
138         cout<<endl;
139     }*/
140     for(int i=0;i<a;++i)
141     {
142         int id=(s[i].x-1)*m+s[i].y;
143     //    addedge(0,id,s[i].tmp); 
144         int snum=0;
145         for(int j=s[i].x+1;j<=n;++j)
146         {
147             if(num[j][s[i].y][0]==0)
148                 break;
149             int count=(j-1)*m+s[i].y;
150             snum++;
151             addedge(id,count,8);
152         }
153         addedge(0,id,s[i].tmp-snum);
154     //    cout<<id<<"  "<<s[i].tmp-snum<<endl;
155     }
156     for(int i=0;i<b;++i)
157     {
158         int id=(t[i].x-1)*m+t[i].y+n*m;
159     //    addedge(id,2*n*m+1,t[i].tmp);
160         int tnum=0;
161         for(int j=t[i].y+1;j<=m;++j)
162         {
163             if(num[t[i].x][j][0]==0)
164                 break;
165             int count=(t[i].x-1)*m+j;
166             tnum++;
167             addedge(count,id,8);
168         }
169         addedge(id,2*n*m+1,t[i].tmp-tnum);
170     //    cout<<id<<"  "<<t[i].tmp-tnum<<endl;
171     }
172     int res=dinic(0,2*n*m+1,2*n*m+2);
173 //    cout<<res<<endl;
174     memset(f,0,sizeof(f));
175     for(int i=2;i<tol;++i)
176     {
177         int c=edge[i].to;
178         int y=c%m;
179         if(y==0)
180             y=m;
181         int x=(c-y)/m+1;
182     //    cout<<x<<" "<<y<<" "<<edge[i].flow<<endl;
183         if(num[x][y][0]==-1&&edge[i].flow>0)
184         {
185         //    cout<<x<<" "<<y<<" "<<edge[i].flow<<endl;
186             f[x][y]+=edge[i].flow;
187         }
188     }
189     for(int i=1;i<=n;++i)
190     {
191         for(int j=1;j<=m;++j)
192         {
193             if(j!=1)
194                 cout<<" ";
195             if(num[i][j][0]==-1)
196                 cout<<f[i][j]+1;
197             else
198                 cout<<"_";
199         }
200         cout<<endl;
201     }
202 }
203      return 0;
204 }
View Code

 

M.       hdu3605       Escape

题意:这题题意很简单,现有n个人要移居到m个星球去,给定一个n*m的矩阵,第 i 行第 j 列如果为1,表示第 i 个人可以去第 j 个星球,如果为0,表示不可以去。

分析:显然是个最大流问题,这题解题的关键在于建图,如果把每个人看做一个点,每个星球看做一个点,人到所有可以去的星球都连上边,那么整个图的边数在10^6,那么就会TLE,那么该怎么建图呢?注意到最多只有10个星球,如果两个人能够居住的星球的情况相同,则可以认为这两个人是同一类人,这样最多只有1024种人,点的数目大大减少,最后将每类人与适合这类人居住的星球建边跑最大流即可。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<cstring>
  5 
  6 using namespace std;
  7 const int MAXN = 201000;
  8 const int MAXM = 1200012;
  9 const int INF = 0x3f3f3f3f;
 10 struct Edge 
 11 {
 12     int to, next, cap, flow;
 13 }edge[MAXM];
 14 int tol;
 15 int head[MAXN];
 16 int gap[MAXN], dep[MAXN], cur[MAXN];
 17 int count[1200];
 18 void init() 
 19 {
 20     tol = 0;
 21     memset(head, -1, sizeof(head));
 22     memset(count,0,sizeof(count));
 23 }
 24 void addedge(int u, int v, int w, int rw = 0) 
 25 {
 26     edge[tol].to = v; edge[tol].cap = w; edge[tol].flow = 0;
 27     edge[tol].next = head[u]; head[u] = tol++;
 28     edge[tol].to = u; edge[tol].cap = rw; edge[tol].flow = 0;
 29     edge[tol].next = head[v]; head[v] = tol++;
 30 }
 31 int Q[MAXN];
 32 void BFS(int start, int end) 
 33 {
 34     memset(dep, -1, sizeof(dep));
 35     memset(gap, 0, sizeof(gap));
 36     gap[0] = 1;
 37     int front = 0, rear = 0;
 38     dep[end] = 0;
 39     Q[rear++] = end;
 40     while(front != end) {
 41         int u = Q[front++];
 42         for(int i = head[u]; i != -1; i = edge[i].next) {
 43             int v = edge[i].to;
 44             if(dep[v] != -1) continue;
 45             Q[rear++] = v;
 46             dep[v] = dep[u] + 1;
 47             gap[dep[v]]++;
 48         }
 49     }
 50 }
 51 int S[MAXN];
 52 int sap(int start, int end, int N) {
 53     BFS(start, end);
 54     memcpy(cur, head, sizeof(head));
 55     int top = 0;
 56     int u = start;
 57     int ans = 0;
 58     while(dep[start] < N) 
 59     {
 60         if(u == end) 
 61         {
 62             int Min = INF;
 63             int inser;
 64             for(int i = 0; i < top; i++)
 65                 if(Min > edge[S[i]].cap - edge[S[i]].flow) {
 66                     Min = edge[S[i]].cap - edge[S[i]].flow;
 67                     inser = i;
 68                 }
 69             for(int i = 0; i < top; i++) 
 70             {
 71                 edge[S[i]].flow += Min;
 72                 edge[S[i]^1].flow -= Min;
 73             }
 74             ans += Min;
 75             top = inser;
 76             u = edge[S[top]^1].to;
 77             continue;
 78         }
 79         bool flag = false;
 80         int v;
 81         for(int i = cur[u]; i != -1; i = edge[i].next) 
 82         {
 83             v = edge[i].to;
 84             if(edge[i].cap - edge[i].flow && dep[v] + 1 == dep[u])                 {
 85                 flag = true;
 86                 cur[u] = i;
 87                 break;
 88             }
 89         }
 90         if(flag) 
 91         {
 92             S[top++] = cur[u];
 93             u = v;
 94             continue;
 95         }
 96         int Min = N;
 97         for(int i = head[u]; i != -1; i = edge[i].next)
 98             if(edge[i].cap - edge[i].flow && dep[edge[i].to] < Min) 
 99             {
100                 Min = dep[edge[i].to];
101                 cur[u] = i;
102             }
103         gap[dep[u]]--;
104         if(!gap[dep[u]]) return ans;
105         dep[u] = Min + 1;
106         gap[dep[u]]++;
107         if(u != start) u = edge[S[--top]^1].to;
108     }
109     return ans;
110 }
111 int n,m;
112 int main()
113 {
114     while(~scanf("%d%d",&n,&m))
115     {
116         init();
117         for(int i=1;i<=n;++i)
118         {
119             int num=0;
120             int c=1;
121             for(int j=1;j<=m;++j)
122             {
123                 int a;
124                 scanf("%d",&a);
125                 num+=c*a;
126                 c=c*2;
127             }
128             count[num]++;
129         }
130         for(int i=0;i<1024;++i)
131         {
132             addedge(0,i+1,count[i]);
133             int num=i;
134             int j=1;
135             while(num>0)
136             {
137                 int a=num%2;
138                 if(a==1)
139                     addedge(i+1,1024+j,count[i]);
140                 num=num/2;
141                 j++;
142             }
143         }
144         for(int i=1;i<=m;++i)
145         {
146             int num;
147             scanf("%d",&num);
148             addedge(1024+i,1024+m+i,num);
149             addedge(1024+m+i,1024+2*m+1,INF);
150         }
151         int ans=sap(0,1024+2*m+1,1024+2*m+2);
152         if(ans==n)
153             cout<<"YES"<<endl;
154         else
155             cout<<"NO"<<endl;
156     }
157     return 0;
158 }
View Code

 

N.       hdu3081      Marriage Match II

题解链接:http://www.cnblogs.com/yaoyueduzhen/p/5087404.html

 

O.       hdu3416      Marriage Match IV

题解链接:http://www.cnblogs.com/yaoyueduzhen/p/5089953.html

 

posted @ 2015-12-05 17:10  邀月独斟  阅读(296)  评论(0编辑  收藏  举报