您的位置:首页 > 其它

【集训Day1 测试】装饰

2017-08-14 11:12 190 查看
装饰(decorate)

【题目描述】

一个图有 N 个结点,编号 1 至 N,有 M 条无向边,第 i 条边连接的两个结点是 Ai 和Bi,其中 Ai 和 Bi 是不同的结点。可能有多条边连接的是同一个点对。现在要给每个结点做标致,每个结点的标志要么是‘F’,要么是‘J’。如果结点 A 和结点 B 之间有边,那么结点 A 和结点 B 的标志就必须不同。做一个‘F’的费用比做一个‘J’的费用要高。所以现在希望用尽量多的‘J’标志要完成任务。输出最多可以用多少‘J’去完成任务。如果不可能完成任务,输出-1。

【输入格式】decorate.in

第一个整数 N 和 M。1 <= N <= 50000,1 <= M <= 100000。

接下来有 M 行,每行两个整数 Ai 和 Bi。

【输出格式】decorate.out

一个整数。

【输入样例】

4 4

12

23

34

41

【输出样例】

2

【解题思路】

利用vector动态数组模拟邻接链表,使a[i][j]表示与i点有连线的所有点。利用深度优先搜索遍历整个图,当前节点标记为f,下一个节点就标记为j,如果说下一个节点在之前已经访问过了,如果说与当前节点的标记相同意味着不可能完成任务,直接break掉并输出-1即可。如果遍历完了之后发现f比j多那么把f和j调换即可。

【参考程序】

#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
vector<int> pic[50001];
bool b[50001],brek;
int c[50001],f,j,n,m,ans,a,d;
void dfs(int point,int fj)
{
b[point]=true;//标记当前节点已被访问
c[point]=fj;//对当前节点进行标记
if (fj==0) f++;//0表示标记f,1表示标记j
else j++;
for (int i=0;i<pic[point].size();i++)//查看所有与当前节点有
4000
连线的点
{
if (!b[pic[point][i]]) dfs(pic[point][i],1-fj);//未被访问就标记并继续遍历
else if (c[pic[point][i]]==fj) //发生冲突
{
brek=true;
return ;
}
}
}
int main()
{
freopen("decorate.in","r",stdin);
freopen("decorate.out","w",stdout);
cin>>n>>m;
for (int i=1;i<=m;i++)
{
cin>>a>>d;
pic[a].push_back(d);
pic[d].push_back(a);
//压入,由于是无向图,所以边的两个端点都要压入。
}
for (int i=1;i<=n;i++)
{
f=j=0;//初始化
if (!b[i]) dfs(i,0);//遍历当前节点可以到达的所有节点。
ans+=max(f,j);
if (brek==true)//如果是冲突break出来的,那么输出-1.
{
cout<<-1;
return 0;
}
}
cout<<ans;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: