1. 程式人生 > >[POI2008] MAF-Mafia

[POI2008] MAF-Mafia

[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 個整數。槍戰後可能的最小和最大的死亡人數。

樣例輸入
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;
}