題意很迷,不過很水。oop
題意:一個房間有m個插座,每一個插座有一個型號,如今有n臺設備,每臺設備指定了一種型號的插座,接下來有k個適配器,能夠代替一種型號的插座。求最少有幾臺設備找不到插座。ui
由於每一個插座只能容許一臺設備接入,因此很容易想到匹配問題,對,開始用二分圖匹配寫的成功AC,而後改爲了最大流,發現最大流建圖更容易,一波板子AC。但兩種寫法都涉及到傳遞閉包,還有題目有個不少小坑點,注意一下就行了。spa
二分圖:code
const int N=800+10; int n,m,k,g[N][N],linked[N],used[N]; void floyd(int num)//傳遞閉包 { // printf("%d\n",num); for(int k=1; k<=num; k++) for(int i=1; i<=num; i++) for(int j=1; j<=num; j++) g[i][j]=g[i][j]||(g[i][k]&&g[k][j]); // for(int i=1;i<num;i++) // for(int j=1;j<num;j++) // printf("i=%d j=%d %d\n",i,j,g[i][j]); } bool dfs(int u) { for(int i=1; i<=m; i++) if(!used[i]&&g[u][i]) { used[i]=1; if(linked[i]==-1||dfs(linked[i])) { linked[i]=u; return true; } } return false; } int hungary() { int res=0; memset(linked,-1,sizeof(linked)); for(int i=m+n+101;i<=m+n+101+n;i++) { memset(used,0,sizeof(used)); if(dfs(i)) res++; } return n-res; } int main() { while(~scanf("%d",&m)) { memset(g,0,sizeof(g)); map<string,int>q; map<string,int>q1; string plug,dev; for(int i=1; i<=m; i++) { cin>>plug; q[plug]=i; } scanf("%d",&n); int tmpn=m+n+100,tmpm=m; for(int i=1; i<=n; i++) { cin>>dev>>plug; q1[dev]=++tmpn; if(!q[plug]) q[plug]=++tmpm; g[q1[dev]][q[plug]]=1; } scanf("%d",&k); for(int i=1; i<=k; i++) { cin>>dev>>plug; if(!q[dev]) q[dev]=++tmpm; if(!q[plug]) q[plug]=++tmpm; g[q[dev]][q[plug]]=1;//單向傳遞 // g[q[plug]][q[dev]]=1; } floyd(tmpn); printf("%d\n",hungary()); } return 0; }最大流:用0做爲源點,與全部設備連邊,容量爲1,設備與對應型號插座連邊,容量爲1,別忘了傳遞閉包。插座和匯點連邊,容量爲1。注意,後出現的插座不能和匯點連邊。
const int N=800+10; int n,m,k; int maze[N][N]; int gap[N],dis[N],pre[N],cur[N]; int flow[N][N]; void floyd(int num)//電器與插頭之間傳遞閉包 { for(int k=1; k<=num; k++) for(int i=1; i<=num; i++) for(int j=1; j<=num; j++) maze[i][j]|=maze[i][k]&&maze[k][j]; } int sap(int s,int t,int num) { memset(cur,0,sizeof(cur)); memset(dis,0,sizeof(dis)); memset(gap,0,sizeof(gap)); memset(flow,0,sizeof(flow)); int u=pre[s]=s,maxflow=0,aug=-1; gap[0]=num; while(dis[s]<num) { loop: for(int v=cur[u]; v<num; v++) if(maze[u][v]-flow[u][v]&&dis[u]==dis[v]+1) { if(aug==-1||aug>maze[u][v]-flow[u][v]) aug=maze[u][v]-flow[u][v]; pre[v]=u; u=cur[u]=v; if(v==t) { maxflow+=aug; for(u=pre[u]; v!=s; v=u,u=pre[u]) { flow[u][v]+=aug; flow[v][u]-=aug; } aug=-1; } goto loop; } int mid=num-1; for(int v=0; v<num; v++) if(maze[u][v]-flow[u][v]&&mid>dis[v]) { cur[u]=v; mid=dis[v]; } if((--gap[dis[u]])==0) break; gap[dis[u]=mid+1]++; u=pre[u]; } return n-maxflow; } int main() { while(~scanf("%d",&m)) { string dev,plug; map<string,int>q; map<string,int>q1; memset(maze,0,sizeof(maze)); //1-n爲電器,101開始都是插頭 //原點爲0,匯點爲301--最壞狀況; int num=100,hui=301; for(int i=1; i<=m; i++) { cin>>plug; q[plug]=++num; maze[q[plug]][hui]=1;//插頭到匯點的容量爲1; } scanf("%d",&n); for(int i=1; i<=n; i++) { cin>>dev>>plug; q1[dev]=i; maze[0][i]=1;//源點到電器,容量爲1 if(!q[plug]) q[plug]=++num; maze[i][q[plug]]=1;//電器到插頭的容量爲1; } scanf("%d",&k); for(int i=1; i<=k; i++) { cin>>dev>>plug; if(!q[dev]) q[dev]=++num; if(!q[plug]) q[plug]=++num; maze[q[dev]][q[plug]]=1; } floyd(300); printf("%d\n",sap(0,301,302)); } return 0; }