poj3436(拆点最大流)
题意:给你p和n,p代表每台计算器需要几个部分组成,n代表有几个组装机器,接下来n行,每行第一个数代表这台机器能够每小时组装几台,剩下前三个数字表示使用这台机器需要的前置条件(0代表当前组装不能有这个部分,1代表得有,2代表无所谓),剩下三个数字表示使用这台机器后的组装有那几个部分,问你最多能组装多少台
解题思路:首先最大流,建立一个超级源点,这个源点和所有前三个数字没有1的机器相连,建立一个超级汇点与所有后三个数字全为1的机器相连,中间所有的机器拆成两个点,边权为这个机器每小时的组装量,拆点的意义就是因为流过这个点的流量有限制
代码:
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #include<queue> using namespace std; const int inf=0x3f3f3f3f; const int maxn=5050; struct sc { int x,y,w; }fna[maxn]; struct node { int val; int x[15]; int y[15]; }a[100]; struct Edge { int fa; int next; int to; int v; int w; }edge[maxn]; int head[maxn],cnt; int pre[maxn],visit[maxn]; int n,p,cot; int Start,End; void add(int u,int v,int w) { edge[cnt].next=head[u];edge[cnt].to=v;edge[cnt].fa=u;edge[cnt].w=w;head[u]=cnt++; edge[cnt].next=head[v];edge[cnt].to=u;edge[cnt].fa=v;edge[cnt].w=0;head[v]=cnt++; } int bfs(int s,int e) { queue<int>q; memset(visit,0,sizeof(visit));memset(pre,-1,sizeof(pre)); q.push(s);visit[s]=1; while(!q.empty()) { int u=q.front();q.pop(); for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].to; if(edge[i].w<=0||visit[v]) continue; pre[v]=i;visit[v]=1; if(v==e) return 1; q.push(v); } } return 0; } int EK() { int ans=0; int sub; while(bfs(Start,End)) { sub=inf; int k=pre[End]; while(k!=-1) { sub=min(sub,edge[k].w); k=pre[edge[k].fa]; } k=pre[End]; while(k!=-1) { edge[k].w-=sub; edge[k^1].w+=sub; k=pre[edge[k].fa]; } ans+=sub; } return ans; } int main() { int vis[150][150]; int flag; memset(head,-1,sizeof(head));cnt=0; memset(vis,0,sizeof(vis)); scanf("%d%d",&p,&n); Start=0;End=2*n+1; for(int i=1;i<=n;i++) { scanf("%d",&a[i].val); for(int j=1;j<=p;j++) scanf("%d",&a[i].x[j]); for(int j=1;j<=p;j++) scanf("%d",&a[i].y[j]); } for(int i=1;i<=n;i++) { add(i,i+n,a[i].val); flag=0; for(int j=1;j<=p;j++) if(a[i].x[j]==1) flag=1; if(flag==0) add(Start,i,a[i].val); flag=0; for(int j=1;j<=p;j++) if(a[i].y[j]!=1) flag=1; if(flag==0) add(i+n,End,a[i].val); } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) { flag=0; if(i==j) continue; for(int k=1;k<=p;k++) { if(a[j].x[k]==2) continue; if(a[j].x[k]!=a[i].y[k]) flag=1; } if(flag==0) { add(i+n,j,a[i].val); vis[i+n][j]=1; } } int ans=EK(); printf("%d ",ans); for(int i=1;i<=n;i++) for(int j=head[i+n];j!=-1;j=edge[j].next) { if(vis[i+n][edge[j].to]&&edge[j].w<a[i].val) cot++; } printf("%d\n",cot); for(int i=1;i<=n;i++) for(int j=head[i+n];j!=-1;j=edge[j].next) { if(vis[i+n][edge[j].to]&&edge[j].w<a[i].val) printf("%d %d %d\n",i,edge[j].to,a[i].val-edge[j].w); } }