SPOJ 18469 UOFTCG

来源:互联网 发布:mac百度云盘怎么卸载 编辑:程序博客网 时间:2024/06/11 19:55

Description
先在要个n个人安排座位,要求是一个人两边不能有不认识的人,两个不认识的人之间必须用一个空座隔开,问最少需要多少座位好
Input
第一行一整数T表示用例组数,每组用例首先输入两整数n和m表示人数和关系数,之后m行每行两个整数u和v表示u和v认识,保证任意k个人之间最多有k-1对人认识(T<=50,n<=1e6)
Output
输出一整数表示最少需要的座位数量
Sample Input
1
6 5
1 2
1 3
1 4
4 5
4 6
Sample Output
7
Solution
贪心,问题其实是把一片森林分成最少的链,对于森林中的每棵树贪心的从底层开始剖分,如果一个节点超过一个可用儿子,那么只能是两个儿子节点(或者说两个儿子节点为祖先的两条链)和这个点组成一个链,其他儿子孤立作为单点链;如果一个节点只有一个可用儿子,那么该节点先和父亲节点连上看往上是否能和其他祖先节点连起来(注意该点如果是根节点那么就没有其他祖先节点连了,所以直接成一条链)
Code

#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>#include<cmath>#include<vector>#include<queue>#include<map>#include<set>#include<ctime>using namespace std;typedef long long ll;#define INF 0x3f3f3f3f#define maxn 111111int T,n,m,vis[maxn],ans,root;vector<int>g[maxn];int dfs(int u){    vis[u]=1;    int num=0;    for(int i=0;i<g[u].size();i++)    {        int v=g[u][i];        if(vis[v])continue;        num+=dfs(v);    }    if(num>=2)    {        ans+=num-1;        return 0;    }    if(u==root)ans++;    return 1;}int main(){    scanf("%d",&T);    while(T--)    {        scanf("%d%d",&n,&m);        for(int i=1;i<=n;i++)g[i].clear();        while(m--)        {            int u,v;            scanf("%d%d",&u,&v);            g[u].push_back(v),g[v].push_back(u);        }        memset(vis,0,sizeof(vis));        ans=0;        for(int i=1;i<=n;i++)            if(!vis[i])root=i,dfs(i);        printf("%d\n",n+ans-1);    }    return 0;}
0 0
原创粉丝点击