网络流 poj 3436 poj 3281
poj 3436
一个电脑有p个部分 n 台机器
n 个机器 每个机器 最多能服务的电脑数目 电脑进来时候需要的 0 代表一定不要 1 一定要 2可有可无 然后就是出去的电脑 0 代表没的 1代表有
超级源点 p 部分没有1 出来的满足进去的条件 都是1 汇点
0 权 两点连 权值是小的 权 n+1
跑一下Dinic
#include<stdio.h> #include<algorithm> #include<cstring> #include<string> #include<cmath> #include<vector> #include<queue> using namespace std; #define MAXN 100 #define inf 1000000000 int head[MAXN]; int z[MAXN],cnt,in[MAXN][15],out[MAXN][15],an[MAXN][MAXN],enu[MAXN*3],env[MAXN*3],enw[MAXN*3]; struct edg { int fr,to,next,w; }edge[300000]; void add(int u,int v,int w) { edge[cnt].fr=u; edge[cnt].to=v; edge[cnt].next=head[u]; edge[cnt].w=w; head[u]=cnt++; } int st,en; int vis[MAXN]; queue<int>q1; bool bfs() { memset(vis,-1,sizeof(vis)); vis[st]=0; q1.push(st); while(!q1.empty()) { int now = q1.front(); q1.pop(); for(int i=head[now];i!=-1;i=edge[i].next) { int v=edge[i].to; if(vis[v]<0&&edge[i].w) { vis[v]=vis[now]+1; q1.push(v); } } } return vis[en]!=-1; } int dfs(int u,int w) { if(u==en) return w; int ans=0; for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].to; if((vis[v]==vis[u]+1)&&edge[i].w) { int b=dfs(v,min(w-ans,edge[i].w)); edge[i].w-=b; edge[i^1].w+=b; an[u][v]+=b; an[v][u]-=b; ans += b; } } return ans; } int main() { int p,n; scanf("%d%d",&p,&n); for(int i=1;i<=n;i++) { scanf("%d",&z[i]); for(int j=1;j<=p;j++) scanf("%d",&in[i][j]); for(int j=1;j<=p;j++) scanf("%d",&out[i][j]); } st =0; en =n+1; cnt=0; memset(head,-1,sizeof(head)); for(int i=1;i<=n;i++) { int ok=0; for(int j=1;j<=p;j++) if(in[i][j]==1) ok=1; if(ok==0) { add(st,i,z[i]); add(i,st,0); } ok=0; for(int j=1;j<=p;j++) ok+=out[i][j]; if(ok==p) { add(i,en,z[i]); add(en,i,0); } } for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(i==j) continue; //进去出来建边 int ok=0; for(int k=1;k<=p;k++) if(out[i][k]+in[j][k]==1) ok=1; if(ok==0) { add(i,j,min(z[i],z[j])); add(j,i,0); } } } int ans=0; while(bfs()) ans += dfs(st,inf); if(ans==0) printf("0 0\n"); else { int cn=0; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) if(an[i][j]>0) { enu[cn]=i; env[cn]=j; enw[cn]=an[i][j]; cn++; } printf("%d %d\n",ans,cn); for(int i=0;i<cn;i++) printf("%d %d %d\n",enu[i],env[i],enw[i]); } return 0; }
n 个牛 F个吃的 D个喝的
一个牛 只能有1个吃的和喝的 一个吃的 只能给一个牛 喝的也是
问 多少牛 有吃的也有喝的
一开始 建图 超级原点 吃的 牛 喝的 超级汇点
结果 GG了 因为这样 有2个吃的 2个喝的 都满足牛 答案是2
所以 牛要拆一下 超级源点 吃的 牛 牛 喝的 超级汇点
权值 1 条件+权值 1 条件+权值 1
#include<stdio.h> #include<algorithm> #include<cstring> #include<string> #include<cmath> #include<vector> #include<queue> using namespace std; #define MAXN 410 #define inf 1000000000 int head[MAXN]; int cnt,S,T; struct edg { int to,w,next; }edge[200000]; void add(int u,int to,int w) { edge[cnt].to=to; edge[cnt].w=w; edge[cnt].next=head[u]; head[u]=cnt++; } queue<int>q1; int vis[MAXN]; bool bfs() { memset(vis,-1,sizeof(vis)); vis[S]=0; q1.push(S); while(!q1.empty()) { int now=q1.front(); q1.pop(); for(int i=head[now];i!=-1;i=edge[i].next) { int v=edge[i].to; if(vis[v]<0&&edge[i].w) { vis[v]=vis[now]+1; q1.push(v); } } } return vis[T]!=-1; } int dfs(int u,int w) { if(u==T) return w; int ans=0; for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].to; if((vis[v]==vis[u]+1)&&edge[i].w) { int b=dfs(v,min(edge[i].w,w-ans)); edge[i].w-=b; edge[i^1].w+=b; ans += b; } } //printf("%d\n",ans); return ans; } int main() { int n,f,d; scanf("%d%d%d",&n,&f,&d); memset(head,-1,sizeof(head)); cnt=0; S=0; T=n*2+f+d+1; for(int i=1;i<=f;i++) { add(S,i,1); add(i,S,0); } for(int i=n*2+f+1;i<=n*2+f+d;i++) { add(i,T,1); add(T,i,0); } for(int i=f+1;i<=n+f;i++) { add(i,i+n,1); add(i+n,i,0); } for(int i=1;i<=n;i++) { int f1,d1; scanf("%d%d",&f1,&d1); for(int j=1;j<=f1;j++) { int a; scanf("%d",&a); add(a,i+f,1); add(i+f,a,0); } for(int j=1;j<=d1;j++) { int a; scanf("%d",&a); add(i+f+n,a+n*2+f,1); add(a+n*2+f,i+f+n,0); } } int ans=0; while(bfs()) ans += dfs(S,inf); printf("%d\n",ans); return 0; }
posted on 2017-03-13 21:15 HelloWorld!--By-MJY 阅读(185) 评论(0) 编辑 收藏 举报