题意: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; typedef long 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 "); 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 ",ans); else printf("impossible "); } return 0; }
举个例子来说:上图的机场编号和关系已经很清楚了(图画的不好,还请见谅,QAQ!)首先先把边为2的确定下来,那么2和4就确定了,再找2所相邻的机场,1,3,5也就确定了。接下来遍历与c=2和c=0无关系的c=1的机场,这时候用二分图涂色法,每次更新比较黑的点和白的点哪一个更小就可以了!看见网上还有用bfs做的,以后找个时间再补上!