Loading

Codeforces 760C:Pavel and barbecue(DFS+思维)

http://codeforces.com/problemset/problem/760/C

题意:有n个盘子,每个盘子有一块肉,当肉路过这个盘子的时候,当前朝下的这一面会被煎熟,每个盘子有两个数,pi代表接下来去第pi个盘子,bi为1的话,这块肉会被反面,0的话这块肉不变。对于每块肉,要让它的两面都在每个盘子里面煎过,问最少的修改次数。

思路:有两个条件:1、让图变得连通最少需要修改的方案。2、要让肉两边都被煎到要怎么考虑。

1、这个简单就是一遍DFS求出连通块数,如果连通块数是1的话,就不需要修改,如果大于1的话,那么需要修改的次数为连通块数。因为我们要把一个连通块的其中一条边指出去到下一个连通块。

2、要让肉两边都煎到,我们可以考虑成从原点出发,下一次回到原点的时候肉要是翻面的。那么,如果这样考虑,我们就只需要让翻面的次数为奇数,这样就可以保证回到原点的时候肉是翻面的了。假设为现在的图已经是连通的了,因为只有n条边,所以每个点都必定有且仅有走过一遍,那么该路径翻面的次数其实就是原来输入的1的数目,所以如果输入的1的数量为偶数的话,答案需要+1,让其变成奇数。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define N 200010
 4 #define INF 0x3f3f3f3f
 5 int p[N], vis[N];
 6 // 1的个数为偶数的时候无法跑到原点是反面,所以要让1的个数变成奇数
 7 // 还有要让图变成联通的,当图已经是联通的时候,不需要变化.当图不联通的话,要修改的边数为联通块数,即将该块的一条边连到另一个联通块
 8 void DFS(int u) {
 9     vis[u] = 1;
10     if(!vis[p[u]]) DFS(p[u]);
11 }
12 
13 int main() {
14     int n;
15     scanf("%d", &n);
16     int cnt = 0, ans = 0, b;
17     for(int i = 1; i <= n; i++) scanf("%d", &p[i]);
18     for(int i = 1; i <= n; i++) {
19         scanf("%d", &b);
20         if(b == 1) cnt++;
21     }
22     if(cnt % 2 == 0) ans++;
23     cnt = 0;
24     for(int i = 1; i <= n; i++) {
25         if(!vis[i]) {
26             cnt++;
27             DFS(i);
28         }
29     }
30     if(cnt == 1) cnt--;
31     ans += cnt; 
32     cout << ans << endl;
33     return 0;
34 }

 

posted @ 2017-02-15 19:48  Shadowdsp  阅读(195)  评论(0编辑  收藏  举报