maxflow最大流/算法导论/挑战程序设计竞赛

流:

源点:s

汇点:t

每条边的容量:容量函数:c(u,v)  (u,v)存在于边中

其图化模式为联通图,。

G的流是一个实值函数f: V*V->R且满足下列三个性质:

容量限制:对所有的 u,v ,f(u,v)<=c(u,v)

反对称性:对所有的 u,v  f(u,v)=-f(v,u)

流守恒性:对所有的u属于V-{s,t}有1.所有流向v的流和为0,2.所以从v流出的流和为0。即流进和和流出的和都为0。

流的定义:|f|=从源点流向v的所有流之和。

 

主体:网络流。

让我们把运输流模拟成网络流吧。

超级源点和超级汇点。c为无穷

残量网络:cf(u,v)=c(u,v)-f(u,v)  cf(v,u)=c(v,u)-f(v,u)    

f(u,v)=-f(v,u)  c(v,u)=0;  cf(v,u)=f(u,v)

f为原网络中的流f'为残量网络中的流|f+f'|=|f|+|f'|

增广路径:cf(p)=min{cf(u,v):(u,v)在p上}

fp(u,v)=cf(p)  (u,v)在p上/-cf(p) (v,u)在p上/0

|fp|=cf(p)>0如果能找到增广路径则继续找,而反向边的存在为了算法纠正自己的错误。

最大流最小割:一个网络的最大流等于其最小割。

所谓割(有向图)就是把网络划分为两个一个包含源点s和一个包含源点t的网络,然后求出所有割中的最小容量即最大流。

净流,和容量。

|f|=c(S,T)某个割即为最小割。

临接表建边的ek算法:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 #include <string>
 5 #include <algorithm>
 6 #include <map>
 7 #include <vector>
 8 using namespace std;
 9 const int N = 1100;
10 const int INF = 0x3f3f3f3f;
11 
12 struct Node
13 {
14     int to;//终点
15     int cap; //容量
16     int rev;  //反向边
17 };
18 
19 vector<Node> v[N];
20 bool used[N];
21 
22 void add_Node(int from,int to,int cap)  //重边情况不影响
23 {
24     v[from].push_back((Node){to,cap,v[to].size()});
25     v[to].push_back((Node){from,0,v[from].size()-1});
26 }
27 
28 int dfs(int s,int t,int f)
29 {
30     if(s==t)
31         return f;
32     used[s]=true;
33     for(int i=0;i<v[s].size();i++)
34     {
35         Node &tmp = v[s][i];  //注意
36         if(used[tmp.to]==false && tmp.cap>0)
37         {
38             int d=dfs(tmp.to,t,min(f,tmp.cap));
39             if(d>0)
40             {
41                 tmp.cap-=d;
42                 v[tmp.to][tmp.rev].cap+=d;
43                 return d;
44             }
45         }
46     }
47     return 0;
48 }
49 
50 int max_flow(int s,int t)
51 {
52     int flow=0;
53     for(;;){
54         memset(used,false,sizeof(used));
55         int f=dfs(s,t,INF);
56         if(f==0)
57             return flow;
58         flow+=f;
59     }
60 }
61 int main()
62 {
63     int n,m;
64     while(~scanf("%d%d",&n,&m))
65     {
66         memset(v,0,sizeof(v));
67         for(int i=0;i<n;i++)
68         {
69             int x,y,z;
70             scanf("%d%d%d",&x,&y,&z);
71             add_Node(x,y,z);
72         }
73         printf("%d\n",max_flow(1,m));
74     }
75 }
View Code

临接矩阵建边的ek算法实现:

 1 #include <cstdio>
 2 #include <vector>
 3 #include <iostream>
 4 #include <queue>
 5 #include <cstring>
 6 
 7 using namespace std;
 8 
 9 #define maxn 105
10 #define inf 0x3f3f3f3f
11 
12 int map[maxn][maxn];
13 int flow[maxn][maxn];
14 int a[maxn],p[maxn];
15 int n;
16 
17 
18 int Ford_fullkerson(int s,int t)
19 {
20     int f=0,u,v;
21     queue<int> qq;
22     memset(flow,0,sizeof(flow));
23     while(1)
24     {
25         memset(a,0,sizeof(a));
26         a[s]=inf;
27         qq.push(s);
28         while(!qq.empty())
29         {
30             u=qq.front();qq.pop();
31             for(v=1;v<=n;v++)
32             {
33                 if(!a[v] && map[u][v]>flow[u][v])
34                 {
35                     p[v]=u;qq.push(v);
36                     a[v]=a[u]<map[u][v]-flow[u][v]?a[u]:(map[u][v]-flow[u][v]);
37                 }
38             }
39         }
40         if(a[t]==0)
41             return f;
42         for(int i=t;i!=s;i=p[i])
43         {
44             flow[i][p[i]]-=a[t];
45             flow[p[i]][i]+=a[t];
46         }
47         f+=a[t];
48     }
49 }
50 
51 int main()
52 {
53     int s,t,c;
54     int cas=1;
55     while(scanf("%d",&n),n)
56     {
57         int x,y,z;
58         memset(map,0,sizeof(map));
59         scanf("%d%d%d",&s,&t,&c);
60         for(int i=0;i<c;i++)
61         {
62             scanf("%d%d%d",&x,&y,&z);
63             map[x][y]+=z;
64             map[y][x]+=z;
65         }
66         printf("Network %d\nThe bandwidth is %d.\n\n",cas++,Ford_fullkerson(s,t));
67     }
68     return 0;
69 }
View Code

 

 Dinic算法实现O(|E|*|V*V|)

 1 #include <cstdio>
 2 #include <vector>
 3 #include <iostream>
 4 #include <queue>
 5 #include <cstring>
 6 #include <algorithm>
 7 using namespace std;
 8 const int N = 300;
 9 const int MAX = 0x3f3f3f3f;
10 #define Min(a,b) a>b?b:a
11 int dis[N];
12 int map[N][N];
13 int m,n;
14 int BFS()  //构建层次网络
15 {
16     memset(dis,-1,sizeof(dis));
17     dis[1]=0;
18     queue<int> v;
19     v.push(1);
20     while(!v.empty())
21     {
22         int x=v.front();v.pop();
23         for(int i=1;i<=n;i++)
24         {
25             if(dis[i]<0 && map[x][i]>0)
26             {
27                 dis[i]=dis[x]+1;
28                 v.push(i);
29             }
30         }
31     }
32     if(dis[n]>0)
33         return 1;
34     else
35         return 0;
36 }
37 int DFS(int x,int low)//Low是源点到现在最窄的(剩余流量最小)的边的剩余流量
38 {
39     int i,a=0;
40     if (x==n)
41         return low;//是汇点
42     for(i=1;i<=n;i++)
43         if (map[x][i] >0 //联通
44             && dis[i]==dis[x]+1 //是分层图的下一层
45             &&(a=DFS(i,min(low,map[x][i]))))//能到汇点(a <> 0)
46         {
47             map[x][i] -= a;
48             map[i][x] += a;
49             return a;
50         }
51         return 0;
52 
53 }
54 
55 int main()
56 {
57     while(~scanf("%d%d",&m,&n))
58     {
59         memset(map,0,sizeof(map));
60         for(int i=0;i<m;i++){
61             int x,y,z;
62             scanf("%d%d%d",&x,&y,&z);
63             map[x][y]+=z;
64         }
65         int ans=0,tmp;
66         while(BFS())
67         {
68             while(tmp=DFS(1,0x3f3f3f3f))
69                 ans+=tmp;
70         }
71         printf("%d\n",ans);
72     }
73     return 0;
74 }
View Code

 

 

uva,820

因为点100个,可能存在多条边,且是无向图。那么O(|E|*|E|*|V|)的复杂度足够了。可以用dinic算法实现,更快。

而且这道题目不能用临接表来做,(因为后向边的编号不知道怎么处理)更正可以处理= =。

因为这里有重边= =不重边情况下不影响,因为编号不同。

因该是因为对于临接表来说每一条边都要建而不是想临接矩阵一样相加就可以了,而且stl储存等等也要花费时间,这里每两个点之间多一条边就是多一对边,至少:200*200*100超时了。

 1 #include <cstdio>
 2 #include <vector>
 3 #include <iostream>
 4 #include <queue>
 5 #include <cstring>
 6 
 7 using namespace std;
 8 
 9 #define maxn 105
10 #define inf 0x3f3f3f3f
11 
12 int map[maxn][maxn];
13 int flow[maxn][maxn];
14 int a[maxn],p[maxn];
15 int n;
16 
17 
18 int Ford_fullkerson(int s,int t)
19 {
20     int f=0,u,v;
21     queue<int> qq;
22     memset(flow,0,sizeof(flow));
23     while(1)
24     {
25         memset(a,0,sizeof(a));
26         a[s]=inf;
27         qq.push(s);
28         while(!qq.empty())
29         {
30             u=qq.front();qq.pop();
31             for(v=1;v<=n;v++)
32             {
33                 if(!a[v] && map[u][v]>flow[u][v])
34                 {
35                     p[v]=u;qq.push(v);
36                     a[v]=a[u]<map[u][v]-flow[u][v]?a[u]:(map[u][v]-flow[u][v]);
37                 }
38             }
39         }
40         if(a[t]==0)
41             return f;
42         for(int i=t;i!=s;i=p[i])
43         {
44             flow[i][p[i]]-=a[t];
45             flow[p[i]][i]+=a[t];
46         }
47         f+=a[t];
48     }
49 }
50 
51 int main()
52 {
53     int s,t,c;
54     int cas=1;
55     while(scanf("%d",&n),n)
56     {
57         int x,y,z;
58         memset(map,0,sizeof(map));
59         scanf("%d%d%d",&s,&t,&c);
60         for(int i=0;i<c;i++)
61         {
62             scanf("%d%d%d",&x,&y,&z);
63             map[x][y]+=z;
64             map[y][x]+=z;
65         }
66         printf("Network %d\nThe bandwidth is %d.\n\n",cas++,Ford_fullkerson(s,t));
67     }
68     return 0;
69 }
View Code
 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <algorithm>
 5 #include <vector>
 6 
 7 using namespace std;
 8 #define maxn 205
 9 #define inf 0x3f3f3f3f
10 
11 struct edge
12 {
13     int to,cap,rev;
14 };
15 
16 vector<edge> G[maxn];
17 bool used[maxn];
18 int n;
19 
20 void add_edge(int from,int to,int cap)
21 {
22     G[from].push_back((edge){to,cap,(int)G[to].size()});
23     G[to].push_back((edge){from,0,(int)G[from].size()-1});
24 }
25 
26 
27 int dfs(int s,int t,int f)
28 {
29     if(s==t)
30         return f;
31     used[s]=true;
32     for(int i=0;i<G[s].size();i++)
33     {
34         edge &e=G[s][i];
35         if(!used[e.to] && e.cap>0)
36         {
37             int d=dfs(e.to,t,min(f,e.cap));
38             if(d>0)
39             {
40                 e.cap-=d;
41                 G[e.to][e.rev].cap+=d;
42                 return d;
43             }
44         }
45     }
46     return 0;
47 }
48 
49 int max_flow(int s,int t)
50 {
51     int flow=0;
52     for(;;)
53     {
54         memset(used,false,sizeof(used));
55         int f=dfs(s,t,inf);
56         if(f==0)
57             return flow;
58         flow+=f;
59     }
60 }
61 
62 int main()
63 {
64     int s,t,c;
65     int cas=1;
66     while(scanf("%d",&n),n)
67     {
68         int x,y,z;
69         scanf("%d%d%d",&s,&t,&c);
70         for(int i=0;i<c;i++)
71         {
72             scanf("%d%d%d",&x,&y,&z);
73             add_edge(x,y,z);
74             add_edge(y,x,z);
75         }
76         printf("Network %d\nThe bandwidth is %d.\n\n",cas++,max_flow(s,t));
77     }
78     return 0;
79 }
临接表超时版,纪念一下

 

 

uva,753

插头和插线板,还有转接器。

以0为源点,然后向所有插线板连一条容量为1的边,最后一个点为汇点,所有电器向汇点连一条容量为1的边。

转换器的插线板和插头之间连一条容量无限的边,因为数量无限。

做简化处理:因为插线板连向电器再连向汇点和插线板直接连向汇点一样,所以中间可以省略。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <queue>
  6 
  7 using namespace std;
  8 #define maxn 1005
  9 #define inf 0x3f3f3f3f
 10 
 11 int n,m,k,tmp;
 12 int g[maxn][maxn];
 13 int f[maxn][maxn];
 14 int t[maxn],rec[maxn];
 15 char name[maxn][maxn];
 16 
 17 
 18 int find(char *ch)
 19 {
 20     for(int i=0;i<tmp;i++)
 21     {
 22         if(strcmp(name[i],ch)==0)
 23             return i;
 24     }
 25     strcpy(name[tmp],ch);
 26     return tmp++;
 27 }
 28 
 29 void init()
 30 {
 31     tmp=1;
 32     memset(g,0,sizeof(g));
 33     memset(f,0,sizeof(f));
 34     memset(name,0,sizeof(name));
 35     
 36     
 37     char ch[maxn],na[maxn];
 38     scanf("%d",&n);
 39     for(int i=0;i<n;i++)
 40     {
 41         scanf("%s",ch);
 42         int p=find(ch);
 43         g[0][p]++;
 44     }
 45     
 46     scanf("%d",&m);
 47     for(int i=0;i<m;i++)
 48     {
 49         scanf("%s%s",na,ch);
 50         int p=find(ch);
 51         rec[i]=p;
 52     }
 53     
 54     scanf("%d",&k);
 55     for(int i=0;i<k;i++)
 56     {
 57         scanf("%s%s",ch,na);
 58         int p=find(ch),q=find(na);
 59         g[q][p]=inf;
 60     }
 61 }
 62 
 63 int solve()
 64 {
 65     for(int i=0;i<m;i++)
 66         g[rec[i]][tmp]++;
 67     int f1=0,u,v;
 68     queue<int> qq;
 69     
 70     while(1)
 71     {
 72         memset(t,0,sizeof(t));
 73         memset(rec,0,sizeof(rec));
 74         t[0]=inf;
 75         qq.push(0);
 76         while(!qq.empty())
 77         {
 78             u=qq.front();qq.pop();
 79             for(v=1;v<=tmp;v++)
 80             {
 81                 if(!t[v] && g[u][v]>f[u][v])
 82                 {
 83                     rec[v]=u;qq.push(v);
 84                     t[v]=min(t[u],g[u][v]-f[u][v]);
 85                 }
 86             }
 87         }
 88         if(t[tmp]==0)
 89             return f1;
 90         for(int i=tmp;i;i=rec[i])
 91         {
 92             f[i][rec[i]]-=t[tmp];
 93             f[rec[i]][i]+=t[tmp];
 94         }
 95         f1+=t[tmp];
 96     }
 97 }
 98 
 99 int main()
100 {
101     int cas;
102     scanf("%d",&cas);
103     while(cas--)
104     {
105         init();
106         printf("%d\n",m-solve());
107         if(cas) printf("\n");
108     }
109     return 0;
110 }
View Code

看来我没有说错。就是这个样子。?

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <algorithm>
  5 #include <queue>
  6 
  7 using namespace std;
  8 #define maxn 1005
  9 #define inf 0x3f3f3f3f
 10 
 11 int n,m,k,tmp;
 12 int g[maxn][maxn];
 13 int f[maxn][maxn];
 14 int t[maxn],rec[maxn];
 15 char name[maxn][maxn];
 16 
 17 
 18 int find(char *ch)
 19 {
 20     for(int i=0;i<tmp;i++)
 21     {
 22         if(strcmp(name[i],ch)==0)
 23             return i;
 24     }
 25     strcpy(name[tmp],ch);
 26     return tmp++;
 27 }
 28 
 29 void init()
 30 {
 31     tmp=1;
 32     memset(g,0,sizeof(g));
 33     memset(f,0,sizeof(f));
 34     memset(name,0,sizeof(name));
 35     
 36     
 37     char ch[maxn],na[maxn];
 38     scanf("%d",&n);
 39     for(int i=0;i<n;i++)
 40     {
 41         scanf("%s",ch);
 42         int p=find(ch);
 43         g[0][p]++;
 44     }
 45     
 46     scanf("%d",&m);
 47     for(int i=0;i<m;i++)
 48     {
 49         scanf("%s%s",na,ch);
 50         int p=find(ch),q=find(na);
 51         g[p][q]++;
 52         rec[i]=q;
 53     }
 54     
 55     scanf("%d",&k);
 56     for(int i=0;i<k;i++)
 57     {
 58         scanf("%s%s",ch,na);
 59         int p=find(ch),q=find(na);
 60         g[q][p]=inf;
 61     }
 62 }
 63 
 64 int solve()
 65 {
 66     for(int i=0;i<m;i++)
 67         g[rec[i]][tmp]++;
 68     int f1=0,u,v;
 69     queue<int> qq;
 70     
 71     while(1)
 72     {
 73         memset(t,0,sizeof(t));
 74         memset(rec,0,sizeof(rec));
 75         t[0]=inf;
 76         qq.push(0);
 77         while(!qq.empty())
 78         {
 79             u=qq.front();qq.pop();
 80             for(v=1;v<=tmp;v++)
 81             {
 82                 if(!t[v] && g[u][v]>f[u][v])
 83                 {
 84                     rec[v]=u;qq.push(v);
 85                     t[v]=min(t[u],g[u][v]-f[u][v]);
 86                 }
 87             }
 88         }
 89         if(t[tmp]==0)
 90             return f1;
 91         for(int i=tmp;i;i=rec[i])
 92         {
 93             f[i][rec[i]]-=t[tmp];
 94             f[rec[i]][i]+=t[tmp];
 95         }
 96         f1+=t[tmp];
 97     }
 98 }
 99 
100 int main()
101 {
102     int cas;
103     scanf("%d",&cas);
104     while(cas--)
105     {
106         init();
107         printf("%d\n",m-solve());
108         if(cas) printf("\n");
109     }
110     return 0;
111 }
View Code

 临接表的好处在于e为正向边,e^1为它的反向边。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <algorithm>
  4 #include <queue>
  5 #include <cstring>
  6 
  7 using namespace std;
  8 
  9 #define maxn 550
 10 #define maxm 50010
 11 #define inf 0x3f3f3f3f
 12 
 13 int n,m,k,s,t,cnt,edgenum;
 14 int first[maxn];
 15 
 16 struct edge
 17 {
 18     int u,v,f,cap,next;
 19 }e[maxm];
 20 
 21 struct divice
 22 {
 23     char s1[30],s2[maxn];
 24 }d[maxn];
 25 
 26 struct adapter
 27 {
 28     char s1[30],s2[30];
 29 }c[maxn];
 30 
 31 struct receptacle
 32 {
 33     char s[30];
 34 }r[maxn];
 35 
 36 
 37 void add_edge(int u,int v,int cap)
 38 {
 39     int t;
 40     e[edgenum].u=u,e[edgenum].v=v;
 41     e[edgenum].f=0,e[edgenum].cap=cap;
 42     e[edgenum].next=first[u];
 43     first[u]=edgenum++;
 44     
 45     t=u;u=v;v=t;
 46     
 47     e[edgenum].u=u,e[edgenum].v=v;
 48     e[edgenum].f=0,e[edgenum].cap=0;
 49     e[edgenum].next=first[u];
 50     first[u]=edgenum++;
 51 }
 52 
 53 
 54 void input()
 55 {
 56     scanf("%d",&n);
 57     for(int i=1;i<=n;i++)
 58         scanf("%s",r[i].s);
 59     scanf("%d",&m);
 60     for(int i=1;i<=m;i++)
 61         scanf("%s%s",d[i].s1,d[i].s2);
 62     
 63     scanf("%d",&k);
 64     for(int i=1;i<=k;i++)
 65         scanf("%s%s",c[i].s1,c[i].s2);
 66     
 67     cnt=n+k+m;
 68 }
 69 
 70 void init()
 71 {
 72     memset(first,-1,sizeof(first));
 73     
 74     s=0,t=cnt+1;
 75     
 76     for(int i=1;i<=m;i++)
 77     {
 78         add_edge(s,i,1);
 79         
 80         for(int j=1;j<=k;j++)
 81             if(!strcmp(d[i].s2,c[j].s1))
 82                 add_edge(i,m+j,inf);
 83         
 84         for(int j=1;j<=n;j++)
 85             if(!strcmp(d[i].s2,r[j].s))
 86                 add_edge(i,j+m+k,1);
 87     }
 88     
 89     for(int i=1;i<=k;i++)
 90     {
 91         for(int j=1;j<=k;j++)
 92         {
 93             if(i!=j && !strcmp(c[i].s2,c[j].s1))
 94                 add_edge(i+m,j+m,inf);
 95         }
 96         
 97         for(int j=1;j<=n;j++)
 98         {
 99             if(!strcmp(c[i].s2,r[j].s))
100                 add_edge(i+m,j+m+k,inf);
101         }
102     }
103     
104     for(int i=1;i<=n;i++)
105         add_edge(i+m+k,t,1);
106 }
107 
108 void ek()
109 {
110     queue<int> q;
111     int f1=0;
112     int a[maxn],path[maxn];
113     
114     while(1)
115     {
116         memset(a,0,sizeof(a));
117         memset(path,-1,sizeof(path));
118         a[s]=inf;q.push(s);
119         while(!q.empty())
120         {
121             int u=q.front();q.pop();
122             for(int i=first[u];i!=-1;i=e[i].next)//临接表所包含元素
123             {
124                 int v=e[i].v;
125                 if(!a[v] && e[i].cap>e[i].f)
126                 {
127                     a[v]=min(a[u],e[i].cap-e[i].f);
128                     path[v]=i;
129                     q.push(v);
130                 }
131             }
132         }
133         
134         if(!a[t])
135             break;
136         
137         for(int i=path[t];i!=-1;i=path[e[i].u])//增广
138         {
139             e[i].f+=a[t];
140             e[i^1].f-=a[t];
141         }
142         f1+=a[t];
143     }
144     printf("%d\n",m-f1);
145 }
146 
147 int main()
148 {
149     int cas;
150     scanf("%d",&cas);
151     while(cas--)
152     {
153         input();
154         init();
155         ek();
156         if(cas) printf("\n");
157     }
158     return 0;
159 }
临接表实现了

 

uva,563

因为一个交叉路口只能被经过一次,所以拆点然后跑一遍ek。

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <queue>
 4 #include <vector>
 5 using namespace std;
 6 
 7 #define INF 9999999
 8 #define MAX 2*52*52+10
 9 vector<int> edge[MAX];
10 int cap[MAX][MAX], flow[MAX][MAX];
11 int bottleneck[MAX], pre[MAX];
12 
13 void BuildGraph(int S, int T, int H, int W);
14 int MaxFlow(int S, int T, int H, int W);
15 
16 int main()
17 {
18     int Case, H, W, B, x, y;
19     scanf("%d", &Case);
20     while (Case--) {
21         scanf("%d %d %d", &H, &W, &B);
22         
23         int S = 0,
24         T = 1;
25         
26         for (int i = 0; i <= 2*(H+1)*W; ++i) edge[i].clear();
27         memset(cap, 0, sizeof(cap));
28         memset(flow, 0, sizeof(flow));
29         
30         BuildGraph(S, T, H, W);
31         
32         for (int i = 0; i < B; ++i) {
33             scanf("%d %d", &x, &y);
34             cap[S][(x*H+y)*2] = 1;
35             edge[S].push_back((x*H+y)*2);
36         }
37         
38         if (MaxFlow(S, T, H, W) == B) puts("possible");
39         else puts("not possible");
40     }
41 }
42 void BuildGraph(int S, int T, int H, int W)
43 {
44     for (int i = 1; i <= H; ++i) {
45         for (int j = 1; j <= W; ++j) {
46             cap[(i*H+j)*2][(i*H+j)*2+1] = 1;
47             edge[(i*H+j)*2].push_back((i*H+j)*2+1);
48             
49             cap[(i*H+j)*2+1][((i-1)*H+j)*2] = 1;
50             edge[(i*H+j)*2+1].push_back(((i-1)*H+j)*2);
51             
52             cap[(i*H+j)*2+1][((i+1)*H+j)*2] = 1;
53             edge[(i*H+j)*2+1].push_back(((i+1)*H+j)*2);
54             
55             cap[(i*H+j)*2+1][(i*H+j-1)*2] = 1;
56             edge[(i*H+j)*2+1].push_back((i*H+j-1)*2);
57             
58             cap[(i*H+j)*2+1][(i*H+j+1)*2] = 1;
59             edge[(i*H+j)*2+1].push_back((i*H+j+1)*2);
60             
61             if (i == 1 || j == 1 || i == H || j == W) {
62                 cap[(i*H+j)*2+1][T] = 1;
63                 edge[(i*H+j)*2+1].push_back(T);
64             }
65         }
66     }
67 }
68 int MaxFlow(int S, int T, int H, int W)
69 {
70     int result = 0;
71     while (1) {
72         memset(bottleneck, 0, sizeof(bottleneck));
73         bottleneck[S] = INF;
74         queue<int> Q;
75         Q.push(S);
76         
77         while (!Q.empty() && !bottleneck[T]) {
78             int now = Q.front();
79             Q.pop();
80             for (int nxt : edge[now]) {
81                 if (!bottleneck[nxt] && cap[now][nxt] > flow[now][nxt]) {
82                     Q.push(nxt);
83                     pre[nxt] = now;
84                     bottleneck[nxt] = min(bottleneck[now], cap[now][nxt] - flow[now][nxt]);
85                 }
86             }
87         }
88         if (bottleneck[T] == 0) break;
89         
90         for (int now = T; now != S; now = pre[now]) {
91             flow[pre[now]][now] += bottleneck[T];
92             flow[now][pre[now]] -= bottleneck[T];
93         }
94         result += bottleneck[T];
95     }
96     return result;
97 }
View Code

 uva,259

二分图最大匹配,匹配到就输出对应的任务数,不能匹配输出'_' 因为任务要全被做完,且一台电脑只能做一个任务且要做一天,电脑最多10台当任务大于10直接不用考虑。

然后就是打印输出,这个想不出来,参考了别人的。主要是今天状态不太好,然后就没去想。。。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <vector>
 5 #include <string>
 6 #include <cstring>
 7 using namespace std;
 8 
 9 int match[10];
10 int cc[0xff];
11 int vis[10];
12 vector<char> G[0xff];
13 
14 int dfs(int u)
15 {
16     for(vector<char>::iterator it=G[u].begin();it!=G[u].end();it++)
17     {
18         int v=*it-'0';
19         if(!vis[v])
20         {
21             vis[v]=1;
22             if(match[v]==-1 || dfs(match[v]))
23             {
24                 match[v]=u;
25                 return 1;
26             }
27         }
28     }
29     return 0;
30 }
31 
32 int main()
33 {
34     while(cin.peek()!=EOF)
35     {
36         int index=0;
37         string line;
38         while(getline(cin,line),isalpha(line[0]))
39         {
40             for(char i='0';i<line[1];i++)
41             {
42                 G[index].clear();
43                 cc[index]=line[0];
44                 for(int j=3;line[j]!=';';j++) G[index].push_back(line[j]);
45                 ++index;
46             }
47         }
48 
49         if(index<=10)
50         {
51             int cnt=0;
52             memset(match,-1,sizeof(match));
53             for(int i=0;i<index;i++)
54             {
55                 memset(vis,0,sizeof(vis));
56                 cnt+=dfs(i);
57             }
58 
59             if(cnt!=index) puts("!");
60             else
61             {
62                 for(int i=0;i<10;i++)
63                 {
64                     if(match[i]==-1) putchar('_');
65                     else
66                         putchar(cc[match[i]]);
67                 }
68                 putchar('\n');
69             }
70         }
71         else
72             puts("!");
73     }
74     return 0;
75 }
View Code

 

 

uva,11380

有容量限制,即存在某个点只允许几个,但是如果这个点允许无数个通过即为无容量限制,对于无容量限制的不需要拆点。

拆点之后跑一次dinic算法,轻松愉快。泰坦尼克号,我就是一炮。

讲一下技巧:这个代码 = =真的简单易懂工整膜拜---

首先只需要对'.'进行拆点,然后超级源点流向'*',  '#'流向超级汇点,'.'拆之后流出的点由拆点流出,

s向所有的'*'连一条边,容量为1,所有的'#'向汇点连一条边容量为p,'.'向拆点连一条边容量为1,拆点'.'向任何有意义的点连一条边容量为1,其余的容量为inf(orz我这一点没想到。。。),然后就是拆点的技巧= =没有想得那么完善= =至于跑算法也没有充分考虑。我感觉ek应该也是可以的,我尝试一下。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <queue>
  4 #include <cctype>
  5 #include <cmath>
  6 #include <cstdlib>
  7 #include <cstring>
  8 #include <string>
  9 #include <set>
 10 #include <vector>
 11 
 12 using namespace std;
 13 
 14 const int N=1e5+10,INF=0x3f3f3f3f;
 15 const int M=1e6+10;
 16 
 17 int head[N],pnt[N],cap[M],nxt[M],cnt;
 18 
 19 void add_edge(int u,int v,int w)
 20 {
 21     pnt[cnt]=v;
 22     cap[cnt]=w;
 23     nxt[cnt]=head[u];
 24     head[u]=cnt++;
 25 }
 26 
 27 void add_double(int u,int v,int w1,int w2=0)
 28 {
 29     add_edge(u,v,w1);
 30     add_edge(v,u,w2);
 31 }
 32 
 33 int lev[N],cur[N];
 34 
 35 bool bfs(int s,int t)//dinic算法效率高
 36 {
 37     queue<int> q;
 38     memset(lev,0,sizeof(lev));
 39     q.push(s);lev[s]=1;
 40     while(q.size() && !lev[t])
 41     {
 42         int u=q.front();q.pop();
 43         for(int i=head[u];~i;i=nxt[i])
 44         {
 45             int v=pnt[i];
 46             if(cap[i]>0 && !lev[v])
 47             {
 48                 lev[v]=lev[u]+1;
 49                 q.push(v);
 50             }
 51         }
 52     }
 53     return lev[t];
 54 }
 55 
 56 int dfs(int u,int t,int delta)
 57 {
 58     if(u==t || !delta) return delta;
 59     
 60     int ret=0;
 61     for(int i=cur[u];~i;i=nxt[i])
 62     {
 63         int v=pnt[i];
 64         if(cap[i]>0 && lev[v]==lev[u]+1)
 65         {
 66             int d=dfs(v,t,min(delta,cap[i]));
 67             cur[u]=i;
 68             ret+=d;delta-=d;
 69             cap[i]-=d;
 70             cap[i^1]+=d;
 71             
 72             if(delta==0) return ret;
 73         }
 74     }
 75     lev[u]=0;
 76     return ret;
 77 }
 78 
 79 int dinic(int s,int t)
 80 {
 81     int ret=0;
 82     while(bfs(s,t))
 83     {
 84         for(int i=s;i<=t;i++)
 85             cur[i]=head[i];
 86         ret+=dfs(s,t,INF);
 87     }
 88     return ret;
 89 }
 90 
 91 int n,m,p;
 92 char a[105][105];
 93 
 94 int get(int x,int y)
 95 {
 96     return m*(x-1)+y;
 97 }
 98 
 99 int d[][2]={-1,0,0,-1,1,0,0,1};
100 
101 bool isIllegal(int x,int y)
102 {
103     return x<1 || x>n || y<1 || y>m;
104 }
105 
106 int main()
107 {
108     while(~scanf("%d%d%d",&n,&m,&p))
109     {
110         for(int i=1;i<=n;i++) scanf("%s",a[i]+1);
111         
112         cnt=0;memset(head,-1,sizeof(head));
113         
114         int s=0,t=2*m*n+1,OFF=n*m;
115         for(int i=1;i<=n;i++)
116             for(int j=1;j<=m;j++)
117             {
118                 if(a[i][j]=='~') continue;
119                 if(a[i][j]=='*') add_double(s,get(i,j),1);
120                 if(a[i][j]=='#') add_double(get(i,j),t,p);
121                 if(a[i][j]=='.') add_double(get(i,j),get(i,j)+OFF,1);
122                 for(int k=0;k<4;++k)
123                 {
124                     int nx=i+d[k][0],ny=j+d[k][1];
125                     if(isIllegal(nx,ny) || a[nx][ny]=='*' || a[nx][ny]=='~') continue;
126 //因为只有'.'需要拆,拆之后由原来点流出的现在由拆点流出。
127                     if(a[i][j]=='.') add_double(get(i,j)+OFF,get(nx,ny),1);
128 //'@'流向任何为无穷,'#'只流向汇点,其他都为inf                    
129                 else add_double (get(i,j),get(nx,ny),INF);
130                 }
131             }
132         printf("%d\n",dinic(s,t));
133     }
134     return 0;
135 }        
View Code

 

转载于:https://www.cnblogs.com/do-it-best/p/5483388.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值