[POI 2008]Mafia

这题目写了我好长时间,但还是几乎(不要在意细节)一遍 A 了喵~

据说有代码奇短的,Orz 思路巧妙的大爷

想我这种 Brute Force 写写的傻 X 真是代码量飞起来了耶,喵~

 

如果把每个人看成点,每个人要 kill 的人向此人连出一条有向边,那么每个点仅有一条出边和一条入边

经验告诉我们,这就是 环+内向图 的节奏

经验又告诉我,处理这种图要么先暴力搞环,再搞挂在环上的树。要么先搞树,再弄环。

此题显然是后者

 

环+内向图只需要用 bfs 就可以搞出来了,看到写 tarjan 的真是 Orz 

弄出 环 和 树 后,先在树上跑 dp,用 dp[u][0] 表示如果 u 最后被 kill 了,那么以 u 为根子树最少要死几人, dp[u][1] 是 u 存活下来的情况

这是普及组难度的树形 dp 吧喵~

再在环上跑 dp ,我们先破环为链,则有3种情况 (我们令在首的人为 A , 在尾的人为 B)

1. A君 最后活着,那 B君 一定被 kill 了

2. A君 最后被 kill 了,B君 存活了或也被 kill 了

3. A君 存活了下来,B君 也存活了下来,然后 B君 kill A君

三种情况要分类讨论

中间过程的状态转移和以上三种情况类似,无非就是讨论 i 君 和 i+1 君 的是否被 kill 的关系  (妈妈说,某个字打出来是不好的喵~)

被 kill 有两种可能:1.被自己的子树中的某君 kill 了  2.被环上的某君 kill 了

这个 dp 也很好想嘛

 

似乎除了难写就没有难度了喵?

 

  1 #include <cstdio>

  2 #include <cstring>

  3 const int size=1000001;

  4 const int inf=size;

  5 

  6 namespace IOspace

  7 {

  8     inline void assign() {freopen("isaac.in", "r", stdin); freopen("isaac.out", "w", stdout);}

  9     inline void close() {fclose(stdin); fclose(stdout);}

 10     inline int getint()

 11     {

 12         register int num=0;

 13         register char ch;

 14         do ch=getchar(); while (ch<'0' || ch>'9');

 15         do num=num*10+ch-'0', ch=getchar(); while (ch>='0' && ch<='9');

 16         return num;

 17     }

 18     inline void putint(int num, char ch='\n')

 19     {

 20         char stack[15];

 21         register int top=0;

 22         if (num==0) stack[top=1]='0';

 23         for ( ;num;num/=10) stack[++top]=num%10+'0';

 24         for ( ;top;top--) putchar(stack[top]);

 25         if (ch) putchar(ch);

 26     }

 27 }

 28 

 29 int n;

 30 int g[size][2];

 31 int t, a[size];

 32 int f[size], d[size];

 33 int dp[size][2];

 34 bool vis[size], loop[size];

 35 

 36 struct edge {int point; edge * next;};

 37 edge MEM[size], * PORT=MEM;

 38 edge * E[size];

 39 inline edge * newedge(int _point, edge * _next)

 40     {edge * ret=PORT++; ret->point=_point; ret->next=_next; return ret;}

 41 

 42 inline int min(int x, int y) {return x<y?x:y;}

 43 inline int max(int x, int y) {return x>y?x:y;}

 44 inline void add(int & x, int y) {if (x>=inf || y>=inf) x=inf; else x+=y;}

 45 inline int search(int);

 46 inline int find(int);

 47 inline void bfs(int);

 48 

 49 int main()

 50 {

 51     int ans1=0, ans2=0;

 52 

 53     n=IOspace::getint();

 54     for (int i=1;i<=n;i++)

 55     {

 56         f[i]=IOspace::getint(), d[f[i]]++;

 57         if (f[i]==i) ans2++, vis[i]=1;

 58         E[f[i]]=newedge(i, E[f[i]]);

 59     }

 60 

 61     for (int i=1;i<=n;i++) if (!d[i])

 62     {

 63         vis[i]=1;

 64         ans2+=search(i);

 65     }

 66     for (int i=1;i<=n;i++) if (!vis[i])

 67     {

 68         vis[i]=1;

 69         ans2+=search(i);

 70     }

 71 

 72     memset(vis, 0, sizeof(vis));

 73     for (int i=1;i<=n;i++) if (!vis[i])

 74     {

 75         vis[i]=1;

 76         ans1+=find(i);

 77     }

 78 

 79     IOspace::putint(ans1, ' '); IOspace::putint(ans2);

 80 

 81     return 0;

 82 }

 83 inline int search(int x)

 84 {

 85     int ret=0;

 86     for (x=f[x];!vis[x];x=f[x]) vis[x]=1, ret++;

 87     return ret;

 88 }

 89 inline void bfs(int x)

 90 {

 91     static int l, r, q[size];

 92 

 93     l=r=0;

 94     for (q[r++]=x;l<r; )

 95     {

 96         int u=q[l++];

 97         for (edge * i=E[u];i;i=i->next)

 98             if (!loop[i->point])

 99             {

100                 vis[i->point]=1;

101                 q[r++]=i->point;

102             }

103     }

104 

105     for (int i=r-1;i>=0;i--)

106         if (E[q[i]]==NULL) dp[q[i]][0]=inf;

107         else if (E[q[i]]->next==NULL && loop[E[q[i]]->point]) dp[q[i]][0]=((E[q[i]]->point)==q[i])?1:inf;

108         else

109         {

110             for (edge * j=E[q[i]];j;j=j->next)

111                 if (!loop[j->point])

112                     add(dp[q[i]][1], dp[j->point][0]);

113             for (edge * j=E[q[i]];j;j=j->next)

114                 if (!loop[j->point])

115                     add(dp[q[i]][0], min(dp[j->point][0], dp[j->point][1]));

116             add(dp[q[i]][0], 1);

117         }

118 }

119 inline int find(int x)

120 {

121     int ret=0;

122 

123     vis[x]=1;

124     for (x=f[x];!vis[x];x=f[x]) vis[x]=1;

125     for (t=0;!loop[x];x=f[x]) loop[a[t++]=x]=1;

126     for (int i=0;i<t;i++) bfs(a[i]);

127     if (t==1) return dp[a[0]][0];

128     g[0][1]=dp[a[0]][1]; g[0][0]=inf;

129     for (int i=1;i<t;i++)

130     {

131         g[i][0]=min(g[i-1][0], g[i-1][1]);

132         add(g[i][0], min(dp[a[i]][0], dp[a[i]][1]+1));

133         g[i][1]=g[i-1][0];

134         add(g[i][1], dp[a[i]][1]);

135     }

136     ret=g[t-1][0];

137 

138     g[0][0]=dp[a[0]][0]; g[0][1]=inf;

139     for (int i=1;i<t;i++)

140     {

141         g[i][0]=min(g[i-1][0], g[i-1][1]);

142         add(g[i][0], min(dp[a[i]][0], dp[a[i]][1]+1));

143         g[i][1]=g[i-1][0];

144         add(g[i][1], dp[a[i]][1]);

145     }

146     ret=min(ret, min(g[t-1][0], g[t-1][1]));

147 

148     g[0][0]=dp[a[0]][1]+1; g[0][1]=inf;

149     for (int i=1;i<t;i++)

150     {

151         g[i][0]=min(g[i-1][0], g[i-1][1]);

152         add(g[i][0], min(dp[a[i]][0], dp[a[i]][1]+1));

153         g[i][1]=g[i-1][0];

154         add(g[i][1], dp[a[i]][1]);

155     }

156     ret=min(ret, g[t-1][1]);

157 

158     return ret;

159 }
因为是考试时写的所以很长也是没办法的事系列

 

你可能感兴趣的:(2008)