BZOJ1124: [POI2008]枪战Maf
1124: [POI2008]枪战Maf
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 501 Solved: 200
[Submit][Status][Discuss]
Description
有n个人,每个人手里有一把手枪。一开始所有人都选定一个人瞄准(有可能瞄准自己)。然后他们按某个顺序开枪,且任意时刻只有一个人开枪。因此,对于不同的开枪顺序,最后死的人也不同。
Input
输入n人数<1000000 每个人的aim
Output
你要求最后死亡数目的最小和最大可能
Sample Input
8
2 3 2 2 6 7 8 5
2 3 2 2 6 7 8 5
Sample Output
3 5
HINT
Source
题解:思路好题;
最小:对于一个入度为0的点,它所指的点一定会死,
于是删除此点及其边,在找入度为0的点,成为子问题,
然后只剩下环,画图发现环的答案为size/2;
最大:对于一条链或者一链+一环都之后剩下一个为死【入度为0的点】
对于一个环也只会留下一个!
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #include<cmath> #define N 1000010 using namespace std; int n,i,j,ans1,ans2,len,h,bo; int die[N],undie[N],q[N],a[N],in[N]; int read() { int x=0,f=1; char ch; while (ch=getchar(),ch<'0'||ch>'9') if (ch=='-') f=-1; while (x=x*10+ch-'0',ch=getchar(),ch>='0'&&ch<='9'); return x*f; } int main() { n=read(); for (int i=1; i<=n; i++) a[i]=read(),in[a[i]]++; for (int i=1; i<=n; i++) { if (in[i]==0) ans1++,q[++ans2]=i; } for (int h=1; h<=ans2; h++) { int i=a[q[h]]; if (die[i]) continue; die[i]=1; undie[a[i]]=1; --in[a[i]]; if (in[a[i]]==0) q[++ans2]=a[i]; } for (int i=1; i<=n; i++) if (in[i]&&!die[i]) { len=bo=0; for (int j=i; !die[j]; j=a[j]) { die[j]=1; ++len; bo|=undie[j]; } if (!bo&&len>1) ++ans1; ans2+=len/2; } printf("%d %d\n",n-ans2,n-ans1); return 0; }
我太蒟蒻了,所以神犇们留下意见让我跪膜