bzoj1124 [POI2008]枪战Maf

Description

有n个人,每个人手里有一把手枪。一开始所有人都选定一个人瞄准(有可能瞄准自己)。然后他们按某个顺序开枪,且任意时刻只有一个人开枪。因此,对于不同的开枪顺序,最后死的人也不同。

Input

输入n人数<1000000 每个人的aim

Output

你要求最后死亡数目的最小和最大可能

Sample Input

8
2 3 2 2 6 7 8 5

Sample Output

3 5
solution
图论题不是网络流之类的板子,一定是有性质的,否则不可做   --------某森林之王
性质:
整个图分为几个联通块,每个块一定是一个仙人球样子的东西
他的刺方向都向球连,每个球一定是 一个简单环或者是自杀的疯子
我们可以贪心
max:
无刺仙人球: n-1
有刺仙人球:n- 刺的端点个数
自杀球:n-刺的端点个数
min:
从 刺的端点(不死)now开始
shoot[now]一定要打死,这样会给后面的疯子更多的生存机会
shoot[shoot[now]]如果indgree==1(没有枝杈)塞入队列
这样把树链贪心完,接近仙人球时
1.当shoot[shoot[now]]==仙人球与刺相接,接点没有必要死,不会进仙人球
2.但是当shoot[now]为接点时,就会进树,进行仙人球内部的贪心
   正是由于这个,仙人球一定会被分成几段,******而刺进入球遍历的一段一定不用再遍历*****
3.最后再把刺没遍历完的球遍历即可
(这个题还有wq的清奇dp思路,但我一下午 被干烧脑了.....)
  1 #include<cstdio>
  2 #include<iostream>
  3 #include<cstring>
  4 #include<queue>
  5 #define mem(a,b) memset(a,b,sizeof(a))
  6 using namespace std;
  7 const int N=1000006;
  8 const int INF=1000500;
  9 inline int minn(int a,int b){return a<b?a:b;}
 10 inline int maxn(int a,int b){return a>b?a:b;}
 11 struct son
 12 {
 13     int v,next;
 14 };
 15 son a1[N<<1];
 16 int first[N<<1],e;
 17 void addbian(int u,int v)
 18 {
 19     a1[e].v=v;
 20     a1[e].next=first[u];
 21     first[u]=e++;
 22 }
 23 /*void addyuan(int u,int v)
 24 {
 25     ayuan[eyuan].v=v;
 26     ayuan[eyuan].next=firstyuan[u];
 27     firstyuan[u]=eyuan++;
 28 }*/
 29 
 30 int n,v[N],fanv[N],maxl,minl;
 31 int now,low[N],dfn[N],sum,num[N],dui[N];
 32 int zhan[N*4],he,flag[N];
 33 int indyuan[N],indtan[N];
 34 int mx,mn,ifzisha[N];
 35 
 36 inline void tan(int x)
 37 {
 38     low[x]=dfn[x]=++now;
 39     zhan[++he]=x;flag[x]=1;
 40     
 41     if(dfn[v[x]]==-1)
 42     {
 43         tan(v[x]);
 44         low[x]=minn(low[v[x]],low[x]);
 45     }
 46     else
 47       if(flag[v[x]])
 48         low[x]=minn(low[x],dfn[v[x]]);
 49     
 50     if(low[x]==dfn[x])
 51     {
 52         ++sum;
 53         while(1)
 54         {
 55             int temp=zhan[he--];
 56             flag[temp]=0;
 57             dui[temp]=sum;
 58             ++num[sum];
 59             if(temp==x)break;
 60         }
 61     }
 62 }
 63 
 64 void finmax()
 65 {
 66     int insum0=0,dian=0;
 67     for(int i=1;i<=n;++i)
 68       if(v[i]==i)
 69         ifzisha[dui[i]]=1;
 70     for(int i=1;i<=sum;++i)
 71     {
 72         if(num[i]==1)
 73         {
 74             if(ifzisha[i])
 75               ++mx;
 76             else
 77             {
 78                 ++dian;
 79                 if(indtan[i]==0)
 80                   ++insum0;
 81             }
 82         }
 83         else
 84         {
 85             if(indtan[i]==0)
 86                 mx+=(num[i]-1);
 87             else
 88               mx+=num[i];
 89         }
 90     }
 91     //printf("insum0=%d dian=%d\n",insum0,dian);
 92     mx+=(dian-insum0);
 93 }
 94 
 95 queue<int> q;
 96 int vis[N];
 97 
 98 void finmin()
 99 {
100     for(int i=1;i<=n;++i)
101     {
102         if(v[i]==i)
103             {++mn;vis[i]=1;}
104         else
105             if(!indyuan[i])
106                 {q.push(i);vis[i]=1;}
107     }
108     //printf("mn=%d\n",mn);
109     while(!q.empty())
110     {
111         int now=q.front();q.pop();
112         //printf("now=%d\n",now);
113         if(vis[v[now]])continue;
114         vis[v[now]]=1;++mn;
115         --indyuan[v[v[now]]];
116         if(indyuan[v[v[now]]]==0&&!vis[v[v[now]]])
117         {
118             vis[v[v[now]]]=1;
119             q.push(v[v[now]]);
120         }
121     }//遍历树链,同时又可以遍历仙人球的环 
122     //cout<<0;
123     //printf("mn=%d\n",mn);
124     for(int i=1;i<=n;++i)
125     {
126         if(vis[i])continue;
127         vis[i]=1;int now=1;
128         for(int j=v[i];;j=v[j])
129         {
130             if(vis[j])break;
131             ++now;vis[j]=1;
132         }
133         mn+=(now+1)/2;
134     }
135 }
136 
137 int main(){
138     //freopen("maf3.in","r",stdin);
139     mem(dfn,-1);
140     mem(first,-1);
141     scanf("%d",&n);
142     for(int i=1;i<=n;++i)
143     {
144         scanf("%d",&v[i]);
145         ++indyuan[v[i]];
146         addbian(v[i],i);
147     }
148     for(int i=1;i<=n;++i)
149       if(dfn[i]==-1)
150         tan(i);
151     
152     /*printf("\n");
153     for(int i=1;i<=n;++i)
154       printf("%d ",dui[i]);
155     printf("\n");*/
156     
157     for(int i=1;i<=n;++i)
158         if(dui[i]!=dui[v[i]])
159           ++indtan[dui[v[i]]];
160     
161     /*printf("indtan=\n");
162     for(int i=1;i<=n;++i)
163       printf("%d ",indtan[i]);
164     printf("\n");*/
165     
166     finmax();
167     finmin();
168     printf("%d %d",mn,mx);
169     while(1);
170     return 0;
171 }
code

 

posted @ 2017-08-02 20:25  A_LEAF  阅读(237)  评论(1编辑  收藏  举报