CF1364D
codeforce 1364D Ehab’s Last Corollary
思想
- 这一题要点是证明无论如何解都存在
- 假如这个图没有环,是一个森林,那么将所有点黑白染色,则颜色多的数量一定大于等于⌈n/2⌉,也就大于等于⌈k/2⌉,符合条件1
- 假如这个图有环,那么一定可以找到一个”最小环“,这个最小环的定义是:环中任何两点除了环上的边,没有其他直连边。找到后,如果这个环中的结点数小于等于k,则符合条件2。如果这个环结点数大于k,那么对这个环间隔取点,取出来的点大于等于⌈k/2⌉,符合条件1
- 算法简介:逐个读边,利用并查集来判断有没有环,假如读完第x条边后发现有环,那么跑一边dfs来提取这个环。此时这个环一定是最小的,但是边还没读完,所以用后面的边来缩小这个环,这样贪心得到的环一定满足“最小环”
代码
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define N 500110
#define M 1010
#define ll long long
using namespace std;
int n,m,k,top,sum,edge,ss;
int f[N],way[N],wout[N],to[N],nxt[N];
int cnt[2],mk[N];
bool book[N];
queue <int> que;
void init()
{
for(int i=1;i<=n;i++) f[i]=i;
}
int getf(int x)
{
if(f[x]==x) return x;
else f[x]=getf(f[x]);
return f[x];
}
void add(int &s,int &e)
{
to[++edge]=e;
nxt[edge]=wout[s];
wout[s]=edge;
}
bool dfs(int x,int fa)
{
if(book[x]) return true;
book[x]=true;
sum++;
for(int i=wout[x];i;i=nxt[i])
{
if(to[i]!=fa && dfs(to[i],x))
{
way[x]=to[i];
return true;
}
}
book[x]=false;
sum--;
return false;
}
void cal(int x,int fa,int col)
{
mk[x]=col;
cnt[col]++;
book[x]=true;
for(int i=wout[x];i;i=nxt[i])
{
if(to[i]!=fa)
cal(to[i],x,col^1);
}
}
int main()
{
int a,b,fa,fb;
scanf("%d%d%d",&n,&m,&k);
init();
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a,&b);
add(a,b);
add(b,a);
fa=getf(a);
fb=getf(b);
if(fa==fb)
{
top=i;
dfs(a,0);
break;
}
f[fa]=fb;
}
if(!top)
{
printf("1\n");
for(int i=1;i<=n;i++)
if(!book[i])
cal(i,0,1);
int l=cnt[1]>cnt[0];
for(int i=1;i<=n;i++)
if(mk[i]==l && top<(k+1)/2)
printf("%d ",i),top++;
printf("\n");
}
else
{
for(int i=top+1;i<=m;i++)
{
scanf("%d%d",&a,&b);
if(book[a] && book[b])
{
for(int j=way[a];j!=b;j=way[j])
{
book[j]=false;
sum--;
}
way[a]=b;
}
}
if(sum<=k)
{
printf("2\n");
printf("%d\n",sum);
for(int i=1;i<=n;i++)
if(book[i])
{
ss=i;
break;
}
for(int i=ss;;i=way[i])
{
printf("%d ",i);
if(way[i]==ss)
{
printf("\n");
break;
}
}
}
else
{
printf("1\n");
for(int i=1;i<=n;i++)
if(book[i])
{
ss=i;
break;
}
for(int i=1,j=ss;i<=(k+1)/2;i++,j=way[way[j]])
printf("%d ",j);
printf("\n");
}
}
return 0;
}
/*
*/