[POI2008] MAF-Mafia

版权声明:神犇使用记得标明出处哦QAQ https://blog.csdn.net/qq_41717018/article/details/83779899

[POI2008] MAF-Mafia

题目描述
n n 个人,每个人手里有一把手枪。 一开始所有人都选定一个人瞄准(有可能瞄准自己)。

然后他们按某个顺序开枪,且任意时刻只有一个人开枪。

因此,对于不同的开枪顺序,最后死的人也不同。

$settle the dispute. Negotiations were very tense, and at one point the trigger-happy participants drew their

guns. Each participant aims at another with a pistol. Should they go on a killing spree, the shooting will go

in accordance with the following code of honour:

 the participants shoot in a certain order, and at any moment at most one of them is shooting, no shooter misses, his target dies instantly, hence he may not shoot afterwards, everyone shoots once, provided he had not been shot before he has a chance to shoot, no participant may change his first target of choice, even if the target is already dead (then the shot causes no further casualties).

An undertaker watches from afar, as he usually does. After all, the mobsters have never failed to stimulate his business. He sees potential profit in the shooting, but he would like to know tight estimations. Precisely he would like to know the minimum and maximum possible death rate. The undertaker sees who aims at whom, but does not know the order of shooting. You are to write a programme that determines the numbers reads from the standard input what target each mobster has chosen, determines the minimum and maximum number of casualties.

输入
1 1 行:人数 1 n 1 , 000 , 000 1\leq n\leq 1,000,000

2 2 行:包含了 n n 个整数 s 1 , s 2 , . . . , s n s i s_{1},s_{2},...,s_{n},s_{i} 表示第i个人瞄准的目标,注意一下第i个的目标可能为 i i

输出
输出 2 2 个整数。枪战后可能的最小和最大的死亡人数。

扫描二维码关注公众号,回复: 4219031 查看本文章

样例输入
8
2 3 2 2 6 7 8 5
样例输出
3 5

题解
一道炒鸡妙的贪心题(退役前的最后挣扎
画个图,猜想一下,可能可以发现:

先按照它给的关系建图。

对于一个大小大于一的环:
最少仅需杀死 s i z e 2 \frac{size}{2} 个人,最多则要杀死 s i z e 1 size-1 个人。

对于死亡最少的:
就是让活下的人最多,对于除了环以外的点,按照拓扑序入队列,而对于已死亡的就不需要入队列了。如果有一个环就只活下一半的人。

对于死亡最多的:
对于一个独立的环,会活下一个人,剩下的只有入度为 0 0 的人能活下。

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+4;
int a[N],n,q[N],in[N],a1,a2,c[N];bool die[N];
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),in[a[i]]++;
	for(int i=1;i<=n;i++) if(!in[i]) a1++,q[++a2]=i;
	for(int i=1;i<=a2;i++){
		int tt=a[q[i]];
		if(die[tt]) continue;
		die[tt]=1; c[a[tt]]=1;
		--in[a[tt]]; 
		if(!in[a[tt]]) q[++a2]=a[tt];
	}
	for(int i=1;i<=n;i++){
		if(in[i]&&!die[i]){
			int L=0,f=0;
			for(int j=i;!die[j];j=a[j]){
				die[j]=1; ++L;
				f|=c[j];
			}
			if(!f&&L>1) a1++;
			a2+=L/2; 
		}
	}
	printf("%d %d\n",n-a2,n-a1);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41717018/article/details/83779899