poj 3281 uva 1658(網路流經典拆點)
阿新 • • 發佈:2018-12-09
題意: 有n只牛,F種食物,D種飲料,每隻牛有自己喜歡吃喝的食物飲料,每種牛隻能吃喝一種食物飲料,每種食物飲料也只能被一隻牛吃喝,現在要計算出滿足牛的需求的最大是多少?
思路: 左邊放食物,右邊放飲料,中間放牛,對於每個牛進行拆點,i和i+100,S向食物點連邊,邊權為1 ,食物點向牛點連邊邊權為1 ,附加點向飲料點連邊邊權為1 ,飲料點向T點連邊,邊權為1 ,那麼對於牛點向 拆出來的點建一條邊權為1 的邊,不然的話,只能保證每種食物飲料只能被一隻牛吃喝,並不能保證每隻牛隻吃喝一種食物。
例如最簡單的例子:
1 2 2 2 2 1 2 1 2
程式碼:
#include<stdio.h> #include<string.h> #include<vector> #include<queue> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; const int N =505; const int inf =0x3f3f3f3f; struct Edge { int from,to,cap,flow; Edge(int u,int v,int c,int f):from(f),to(v),cap(c),flow(f){} }; struct Dinic { int n,m,s,t; vector< Edge >edges; vector< int >G[N]; bool vis[N]; int d[N]; int cur[N]; void init() { for (int i=0; i<N; i++) G[i].clear(); edges.clear(); } void addedge(int from,int to,int cap) { edges.push_back(Edge(from,to,cap,0)); edges.push_back(Edge(to,from,0,0)); m=edges.size(); G[from].push_back(m-2); G[to].push_back(m-1); } bool bfs() { memset(vis,0,sizeof(vis)); queue<int >q; for (int i=0; i<N; i++) d[i] = inf; q.push(s); d[s]=0;vis[s]=1; while(!q.empty()){ int x=q.front(); q.pop(); for(int i=0;i<G[x].size();i++){ Edge e=edges[G[x][i]]; if(!vis[e.to]&&e.cap>e.flow){ vis[e.to]=1; d[e.to]=d[x]+1; q.push(e.to); } } } return vis[t]; } int dfs(int x,int a) { if(x==t||a==0) return a; int flow=0,f; for(int &i=cur[x];i<G[x].size();i++){ Edge &e=edges[G[x][i]]; if(d[x]+1==d[e.to]&&(f=dfs(e.to,min(a,e.cap-e.flow)))>0){ e.flow+=f; edges[G[x][i]^1].flow-=f; flow+=f; a-=f; if(a==0) break; } } return flow; } int maxflow(int s,int t) { this->s=s; this->t=t; int flow=0; while(bfs()){ memset(cur,0,sizeof(cur)); flow+=dfs(s,inf); } return flow; } }a; int f,d; int n,m; int F,D; int main() { scanf("%d %d %d",&n,&F,&D); a.init(); int S,T; T=501; S=0; for(int i=1;i<=F;i++){ a.addedge(S,i,1); } for(int i=1;i<=D;i++){ a.addedge(300+i,T,1); } for(int i=1;i<=n;i++){ scanf("%d %d",&f,&d); int x; for(int j=1;j<=f;j++){ scanf("%d",&x); a.addedge(x,i+100,1); } for(int j=1;j<=d;j++){ scanf("%d",&x); a.addedge(200+i,300+x,1); } a.addedge(100+i,200+i,1); } int ans=a.maxflow(S,T); printf("%d\n",ans); return 0; } /* 1 2 2 2 2 1 2 1 2 */
uva 1658
題意: 求1點到n點的兩條不相交的路徑,並且要求路徑長度最小。
思路: 因為兩條路徑不相交,所以除了1點和n點,其他所有的點和邊只能走一次。但是如果我們僅僅對邊限制,是不能保證點只走一次的,所以要按上邊的方法,對點進行拆點。
程式碼:
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int inf =0x3f3f3f3f; const int N =2005; struct Edge { int u,v; int cap,flow; int cost; }; struct MCMF { int n,m,s,t; vector<Edge>edges; vector<int >G[N]; int inq[N]; int d[N]; int p[N]; int a[N]; void init(int n) { this->n=n; for(int i=0; i<=n+2; i++) { G[i].clear(); } edges.clear(); } void adde(int u,int v,int cap,int cost) { edges.push_back((Edge){u,v,cap,0,cost}); edges.push_back((Edge){v,u,0,0,-cost}); m=edges.size(); G[u].push_back(m-2); G[v].push_back(m-1); } bool spfa(int s,int t,int &flow,int &cost) { for(int i=0; i<=n+2; i++)d[i]=inf; memset(inq,0,sizeof(inq)); d[s]=0; inq[s]=1; p[s]=0; a[s]=inf; queue<int >q; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); inq[u]=0; for(int i=0; i<G[u].size(); i++) { Edge &e=edges[G[u][i]]; if(e.cap>e.flow&&d[e.v]>d[u]+e.cost) { d[e.v]=d[u]+e.cost; p[e.v]=G[u][i]; a[e.v]=min(a[u],e.cap-e.flow); if(!inq[e.v]) { q.push(e.v); inq[e.v]=1; } } } } if(d[t]==inf) return 0; flow+=a[t]; cost+=d[t]*a[t]; int u=t; while(u!=s) { edges[p[u]].flow+=a[t]; edges[p[u]^1].flow-=a[t]; u=edges[p[u]].u; } return 1; } void mincost_maxflow(int s,int t,int& flow,int & cost) { flow=0; cost=0; while(spfa(s,t,flow,cost)); } } a; int n,m; int main() { int u,v,w; while(scanf("%d %d",&n,&m)!=EOF) { a.init(2*n+2); int S=1; int T=2*n; for(int i=1;i<=n;i++){ if(i==1||i==n){ a.adde(i,i+n,2,0); } else a.adde(i,i+n,1,0); } for(int i=1;i<=m;i++){ scanf("%d %d %d",&u,&v,&w); a.adde(u+n,v,1,w); } int flow,cost; flow=cost=0; a.mincost_maxflow(S,T,flow,cost); printf("%d\n",cost); } return 0; } /* 6 11 1 2 23 1 3 12 1 4 99 2 5 17 2 6 73 3 5 3 3 6 21 4 6 8 5 2 33 5 4 5 6 5 20 */