補題——Spring Training Series B 1st Round-A Gym - 100502A
阿新 • • 發佈:2019-05-15
break its spa names false turn 就是 tdi article
題意:n個機場,m條關系,每個關系又a,b,c三個數,分別代表a和b兩個機場間要建立c個休息室,讓你求所建休息室最小的數目,如果不可能則輸出impossible
思路:先把兩個點之間c為0和2的都確定下來,再考慮1的情況。剩下的就是判斷二分圖(塗色法:https://blog.csdn.net/li13168690086/article/details/81506044),因為剩下的就是兩個點間為1的情況;
#include <cstdio> #include<bits/stdc++.h> const int maxnn = 3000000; using namespace std; typedeflong long ll; vector<int> p[maxnn]; int sum,ans,n,m; int vis[maxnn],x[maxnn],y[maxnn];//vis代表機場的狀態,-1表示未遍歷,0表示該機場沒有休息室,1表示該機場有休息室。x[]記錄有1個休息室邊的機場編號,y[]記錄有0個休息室的機場編號; bool dfs(int x)//搜索當前機場所連接的其他機場 { for(int i=0;i<p[x].size();i++) { int v=p[x][i]; if(vis[v]!=-1) {if(vis[v]==vis[x])return false;//由於c等於0和等於2的點都已經被標記過了,現在便利的就是c等1情況的,如果當前vis[v]的值和vis[x]的值一樣,說明不可能滿足條件。 } else { vis[v]=!vis[x];//把相鄰的點塗成和該顏色機場相反的點 sum++;//記錄所有的節點 if(vis[v])ans++; if(!dfs(v))return false;//如果該機場的相鄰的某個機場和它相鄰的機場顏色相同則不滿足條件; } }return true;//如果都滿足則返回ture } int main() { int len1=0,len2=0,f=1; scanf("%d%d",&n,&m); fill(vis+1,vis+n+1,-1); for(int i=0;i<m;i++) { int a,b,c; scanf("%d%d%d",&a,&b,&c); if(c==2) { if(vis[a]==-1) { vis[a]=1; ans++;//休息室的個數 x[len1++]=a;//記錄需要在改機場建立1個休息室的機場編號; } else if(!vis[a])f=0;//如果當前已經被訪問即被標記為0的時候,說明當前這條邊的值為0,而現在又要在該機場再建一個休息室,肯定是不符合條件的。 if(vis[b]==-1) { vis[b]=1; ans++; x[len1++]=b;//同上 } else if(!vis[b])f=0;//同上 } else if(c==0) { if(vis[a]==-1) { vis[a]=0; y[len2++]=a;//記錄需要在改機場建立0個休息室的機場編號; } else if(vis[a])f=0;//如果當前已經被訪問即被標記為1的時候,說明當前這條邊的值為2,而現在又要在該機場建一個休息室,肯定是不符合條件的。 if(vis[b]==-1) { vis[b]=0; y[len2++]=b; } else if(vis[b])f=0; } else { p[a].push_back(b);//其他的構建鄰接表 p[b].push_back(a); } } if(!f)//如果以上條件又不符合的 printf("impossible\n"); else { for(int i=0;i<len1;i++) { if(!dfs(x[i]))//搜索當前機場休息室為0的點,對於每一個機場可能有其他機場與他的邊值c=1,需要在判斷一下是否滿足條件; { f=0; break; } } for(int i=0;i<len2;i++) { if(!dfs(y[i]))//同理搜索為1的機場 { f=0; break; } } for(int i=1;i<=n;i++) { if(vis[i]!=-1)continue;//搜索過的就不用了,這一步主要判斷單獨的聯通塊(c=1且與c=2和c=0的機場無任何聯系) vis[i]=1; sum=1; int now=ans++; if(!dfs(i)) { f=0;//如果有不符合的,標記 break; } ans=min(ans,sum-ans+now+now);//比較塗色為0,和1兩個點的最小值,每次而更新最小; } if(f)printf("%d\n",ans); else printf("impossible\n"); } return 0; }
舉個例子來說:上圖的機場編號和關系已經很清楚了(圖畫的不好,還請見諒,QAQ!)首先先把邊為2的確定下來,那麽2和4就確定了,再找2所相鄰的機場,1,3,5也就確定了。接下來遍歷與c=2和c=0無關系的c=1的機場,這時候用二分圖塗色法,每次更新比較黑的點和白的點哪一個更小就可以了!看見網上還有用bfs做的,以後找個時間再補上!
補題——Spring Training Series B 1st Round-A Gym - 100502A