【2023.03.17】Luogu P5870 [SEERC2018]Modern Djinn 题解

1.题目

你不是一个 leader,你是一个 president。幸运的是,你有一只精灵,能够实现你的愿望。你的其中一个愿望就是假装你的社会中有 democracy。


社会很简单。社会里有 N N N 个人,编号从 1 1 1 N N N,一些人“开心”而另一些很平常(“不开心”)。人类这种生物非常奇妙,人们只在别人不开心时才感到开心。人们共有 M M M 个愿望,编号从 1 1 1 M M M X → Y X \rightarrow Y XY代表 X X X 想要 Y Y Y 不开心。一个人 X X X 是开心的当且仅当他的至少一个愿望得到满足。


Democracy 也没那么复杂。有些人说为了实现 democracy,你需要至少一半的人是开心的(或一半的愿望得到满足),但这不全是事实。我刚才说过,你是一个好的 president,而不是一个好的 leader。你可以通过媒体来定义 democracy。因此,在所有的 M M M 个愿望中,你决定实现至少 ⌊ M / 4 ⌋ + 1 \lfloor M/4 \rfloor +1 M/4+1 个愿望。


剩下的事情就是选出你想实现的愿望,然后精灵会处理好一切。


2.输入

输入包含多组测试数据。第一行包含一个整数 T T T,代表测试数据的组数。接下来的输入中会按顺序给出每组测试数据。

在每组测试数据中,第一行包含两个正整数 N N N M M M,代表社会中人的数量和愿望的数量。接下来 M M M 行每行包含两个整数 X , Y X, Y X,Y,描述了一个愿望: X X X 希望 Y Y Y 不开心。

3.输出

对于每组测试数据,第一行输出一个整数 K K K,代表实现的愿望的数量,第二行输出 K K K 个整数,代表实现的愿望编号,输出的顺序不做限制。


样例

输入

  2
  3 3
  1 2
  2 3
  3 1
  4 4
  1 2
  2 3
  3 4
  1 4

输出

  1
  2
  2
  1 4

4.提示

【数据范围与限制】

  • 1 ≤ T ≤ 10 , 000 1 \leq T \leq 10, 000 1T10,000

  • 2 ≤ N ≤ 100 , 000 2 \leq N \leq 100,000 2N100,000

  • 1 ≤ M ≤ 200 , 000 1 \leq M \leq 200,000 1M200,000

  • 不存在 X X X 希望 X X X 不开心这样的愿望。

  • 可能存在多个相同的 X X X 希望 Y Y Y 不开心的愿望。

  • 每组数据保证解一定存在。

  • 输出任何正确的解都可以。

【样例解释】

第一组测试数据中,我们可以实现最多 1 1 1 个愿望,输出任意一个愿望都是可行的。

第二组测试数据中,另外一个可行的解是实现愿望 1 , 3 1, 3 1,3 4 4 4,最少需要实现 2 2 2 个愿望。

emmmmmmmm,蒟蒻表示看不懂……

5.简化题意

给每个点黑白染色,然后一条边合法当且仅当起点为黑色终点为白色,要使得合法边数量大于等于 ⌊M / 4⌋ + 1 。

转载至 xiaolilsq

6.做法

其实一开始就没半点思路,后来思考半天后百度了一下,在某大佬的博客中找到一句话:

要满足愿望的数量并不多,随机给每个点染色即可。

emmmmmmmmm……这能过吗?

???

7.代码

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5;
int n;
int m;
int t;
int num;
int tot;
int flag;
int a[N];
struct node{
	int x,y;
}b[N];
inline int read(){
	register int s=0;
	register int w=1;
	char ch;
	ch=getchar();
	while(ch<'0'||ch>'9'){
		if(ch=='-'){
			w=-1;
		}
		ch=getchar();
	}
	while(ch>='0'&&ch<='9'){
		s=(s<<1)+(s<<3)+(ch^48);
		ch=getchar();
	}
	return s*w;
}
inline void write(int s){
    register int len=0;
    char ch[20];
    if(s<0){
        putchar((1<<5)+(1<<3)+(1<<2)+1);
        s=~s+1;
    }
    do{
        ch[len++]=s%10+(1<<4)+(1<<5);
        s/=10;
    }while(s>0);
    for(int i=len-1;i>=0;i--){
        putchar(ch[i]);
    }
    return ;
}
int main(){
	//freopen(".in","r",stdin);
	//freopen(".out","w",stdout);
	t=read();
	while(t--){
		n=read();
		m=read();
		for(int i=1;i<=m;i++){
			b[i].x=read();
			b[i].y=read();
		}
		tot=0;
		num=m/4+1;
		while(tot<num){
		    tot=0;
			for(int i=1;i<=n;i++){
		    	a[i]=rand()%2;
		    }
			for(int i=1;i<=m;i++){
				if((a[b[i].x]==true)&&(a[b[i].y]==false)){
					++tot;
				}
			}
		}
		write(tot);
		putchar('\n');
		flag=0;
		for(int i=1;i<=m;i++){
			if(a[b[i].x]&&!a[b[i].y]){
				if(!flag){
					flag=1;
				}
				else{
					putchar(' ');
				}
				write(i);
			}
		}
		putchar('\n');
	}
	//fclose(stdin);
	//fclose(stdout);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值