题目链接:https://odzkskevi.qnssl.com/7bdafb89605bd39aff640413e2d2157a?v=1488601228。
题意:大意就是有n个飞机场,每个飞机场可能有个休息室,然后给你m组关系,每组关系有3个数x,y,z,表示若z=0,表示x、y飞机场都没有休息室。若z=1,表示x、y其中有一个有休息室,若z=2,表示两个都有休息室。问总共最少有几个休息室。
思路:讲道理这题不难,就是比较烦。很明显题目看完就能想到,这是一个判断是否是二分图的问题,用染色法解决就好了。但是他要求出最少的休息室是多少,这里比较难说明怎么处理,看代码吧:
#include <bits/stdc++.h>
using namespace std;
const int MAXN=2e5+7;
int n,m;
int vis[MAXN],x[MAXN],y[MAXN],sum,ans;
vector<int>head[MAXN];
bool dfs(int u)
{
for(int i=0,l=head[u].size(); i<l; ++i)
{
int v=head[u][i];
if(vis[v]!=-1)
{
if(vis[v]==vis[u])return 0;
}
else
{
vis[v]=!vis[u];
sum++;
if(vis[v])ans++;
if(!dfs(v))return 0;
}
}
return 1;
}
int main()
{
scanf("%d%d",&n,&m);
fill(vis+1,vis+1+n,-1);
int len1=0,len2=0;
bool flag=1;
while(m--)
{
int u,v,z;
scanf("%d%d%d",&u,&v,&z);
if(z==2)
{
if(vis[u]==-1)
{
vis[u]=1;
ans++;
x[len1++]=u;
}
else if(!vis[u])flag=0;
if(vis[v]==-1)
{
vis[v]=1;
ans++;
x[len1++]=v;
}
else if(!vis[v])flag=0;
}
else if(z==0)
{
if(vis[u]==-1)
{
vis[u]=0;
y[len2++]=u;
}
else if(vis[u])flag=0;
if(vis[v]==-1)
{
vis[v]=0;
y[len2++]=v;
}
else if(vis[v])flag=0;
}
else
{
head[u].push_back(v);
head[v].push_back(u);
}
}
if(!flag)return 0*puts("impossible");
for(int i=0; i<len1; ++i)
{
if(!dfs(x[i]))
{
flag=0;
break;
}
}
for(int i=0; i<len2; ++i)
{
if(!dfs(y[i]))
{
flag=0;
break;
}
}
for(int i=1; i<=n; ++i)
{
if(vis[i]!=-1)continue;
vis[i]=1;
sum=1;
int now=ans++;
if(!dfs(i))
{
flag=0;
break;
}
ans=min(ans,sum-ans+now+now);//ans代表是now+涂颜色1的,后面now+sum-(ans-now)代表的是涂颜色0的,我们取一个较小的值。
//ans-now代表新增的颜色1,sum代表总点数,相减代表新增颜色0的个数。
//这里每次检验的其实就是一个单独的联通块。每次更新上加的最小值
}
if(flag)printf("%d\n",ans);
else puts("impossible");
return 0;
}
染色我想就不用多说了。判断是否是符合题意的。
这里是直接学习了别人的代码,看了一晚上,终于搞懂了作者的思路是什么了。
判断是否是二分图,运用0,1染色。