POJ 1087 A Plug for UNIX 最大流
本题关键是建图,然后SAP水一个
建图:设0为源点,1为汇点,所以检索表里的插头下标要从2开始。
先输入n个插座,每个插座与汇点相连,值为1。
再输入m个用电器,用电器的名称其实是个无用的信息,把每个用电器的插头与源点相连,值为1。
然后输入k个转换器,如B X,则B与X连,注意值为INF(无穷大),因为这种类型的转换器可以有无数个。
最后SAP水一个,水题鉴定完毕。
View Code
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; #define INF 100000000 #define maxn 405 //莫名其妙的RE,无奈开到405 #define maxm 305 int tot,head[maxn]; struct node { int v, next ,c; }edge[maxm * 2]; //双向别忘了*2; int dis[maxn],num[maxn]; int cur[maxn],pre[maxn]; int n, m, k, s, t, vs; void add(int x, int y, int c) { edge[tot].v=y; edge[tot].c=c; edge[tot].next=head[x]; head[x]=tot++; edge[tot].v=x; edge[tot].c=0; edge[tot].next=head[y]; head[y]=tot++; } int cnt; char id[maxn][40],s1[40],s2[40]; int sap() //sap非递归 { memset(dis,0,sizeof(dis)); memset(num,0,sizeof(num)); num[0]=vs=cnt; int i, u=pre[s]=s,aug=INF,v,maxf=0; for(i=0;i<=cnt;i++)cur[i]=head[i]; while(dis[s] < vs) { loop: for(i=head[u];i!=-1;i=edge[i].next) { v = edge[i].v; if(edge[i].c>0&&dis[u]==dis[v]+1) { aug=min(aug,edge[i].c); pre[v]=u; cur[u]=i; u=v; if(u == t) { for(u=pre[u];v!=s;v=u,u=pre[u]) { edge[cur[u]].c -= aug; edge[cur[u]^1].c += aug; } maxf += aug; aug=INF; } goto loop; } } int mind=vs; for(i=head[u];i!=-1;i=edge[i].next) { v = edge[i].v; if(dis[v]<mind&&edge[i].c>0) { mind=dis[v]; cur[u]=i; } } if(!(--num[dis[u]]))break; ++num[dis[u]=mind+1]; u=pre[u]; } return maxf; } int find(char *s) //建立检索表,找编号 { int i; for(i=2;i<cnt;i++) if(!strcmp(id[i],s))return i; strcpy(id[i],s); return cnt++; } int main() { int i; while(~scanf("%d",&n)) { cnt=2;s=0;t=1; //0为源点,1为汇点。 memset(head,-1,sizeof(head)); tot=0; for(i=1;i<=n;i++) { scanf("%s",s1); add(find(s1),t,1); } scanf("%d",&m); for(i=1;i<=m;i++) { scanf("%s%s",s1,s2); add(s,find(s2),1); } scanf("%d",&k); for(i=1;i<=k;i++) { scanf("%s%s",s1,s2); add(find(s1),find(s2),INF);//注意INF } printf("%d\n",m-sap()); } }


浙公网安备 33010602011771号