【treedp】2010final F.Keys
https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&category=547&page=show_problem&problem=4042k
真的不明白自己为什么会老犯a打成b之类的sb错误=。=~~。打错字母再次卡了一个多钟!!!
给你一系列钥匙跟钥匙环,钥匙系在钥匙环上,钥匙环可以系在一起组成一个森林结构。。每次操作有2种分别是把钥匙从环上解下或系上,另外一种是把环与环解开或系上。。。要求最少的操作次数将A-M的钥匙弄在同一棵由环组成的树上,同时N-Z的钥匙需要再另外一棵树上。。这里最少操作数是指保证第一种操作最少的同时第二种最少。
做法很简单,每个环分别统计其上两种钥匙的数量,将其分成3种环,或者是属于A-M钥匙的0类环,或者是属于N-Z的1类环,或者都可以的2类环。。再进行一个简单dp即可。。这里要主要一下dp前要保证至少有1个0类环以及至少有1个1类环,如不满足可以通过枚举来强制转换环的类型。另外再把其中一类钥匙没出现的情况,还有无解情况特判掉。。
View Code
1 //By Lin 2 #include<cstdio> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<set> 7 #include<vector> 8 #include<map> 9 #include<queue> 10 11 #define sqr(x) ((x)*(x)) 12 #define Rep(i,n) for(int i = 0; i<n; i++) 13 #define foreach(i,n) for( __typeof(n.begin()) i = n.begin(); i!=n.end(); i++) 14 #define X first 15 #define Y second 16 #define mp(x,y) make_pair(x,y) 17 18 using namespace std; 19 typedef long long LL; 20 typedef pair<int,int> pii; 21 #define N 30 22 #define inf 0x7fffffff 23 int ecnt; 24 struct Edge{ 25 int to; 26 Edge *next; 27 }*mat[N],edges[N*2]; 28 void link(int x,int to){ 29 edges[ecnt].to = to; 30 edges[ecnt].next = mat[x]; 31 mat[x] = &edges[ecnt++]; 32 } 33 34 int dp[30][2][2]; 35 int kind[30]; 36 int num[30][2],n,mm[N],tol[2]; 37 char str[N]; 38 bool mark[N]; 39 40 void check(int &x,int y){ 41 if ( x == -1 || x > y ) x = y; 42 } 43 int id(char ch){ 44 int k = ch-'a'; 45 if ( mm[k] == -1 ) mm[k] = n++; 46 return mm[k]; 47 } 48 bool dfs(int x,int father){ 49 mark[x] = true; 50 memset( dp[x] , 0 , sizeof(dp[x]) ); 51 bool ret = num[x][0]+num[x][1]>0; 52 for ( Edge *p = mat[x]; p ; p = p->next ){ 53 int to = p->to; 54 if ( to == father ) continue; 55 ret |= dfs(to,x); 56 Rep(i,2) Rep(j,2){ 57 if ( kind[x]<2 && kind[x]!=i ) continue; 58 if ( (num[x][0]+num[x][1]>0 || kind[x]<2 )&& j == 0 ) continue; 59 int tmp = inf; 60 Rep(g,2) Rep(h,2){ 61 if ( kind[to]<2 && kind[to]!=g ) continue; 62 if ( (num[to][0]+num[to][1]>0 || kind[to]<2 ) && h == 0 ) continue; 63 int K = 0; 64 if ( h == 1 && j == 0 ) K = 2; 65 else if ( i != g ) K = 1+(h?1:0); 66 tmp = min( tmp , dp[to][g][h]+K ); 67 } 68 dp[x][i][j] += tmp; 69 } 70 } 71 // printf("%d kind %d\n" , x , kind[x] ); 72 // Rep(i,2) Rep(j,2){ 73 // if ( kind[x]<2 && kind[x]!=i ) continue; 74 // if ( (num[x][0]+num[x][1]>0 || kind[x]<2 )&& j == 0 ) continue; 75 // printf("dp[%d][%d][%d]= %d\n", x, i , j , dp[x][i][j] ); 76 // } 77 return ret; 78 } 79 80 int solve(){ 81 int ret = 0; 82 memset( mark , false , sizeof(mark) ); 83 Rep(i,n){ 84 if ( mark[i] ) continue; 85 dfs(i,-1); 86 int tmp = inf; 87 Rep(g,2) Rep(h,2){ 88 if ( kind[i]<2 && kind[i]!=g ) continue; 89 if ( (num[i][0]+num[i][1]>0 || kind[i]<2 ) && h == 0 ) continue; 90 // printf("%d %d val %d\n" , g , h , dp[i][g][h] ); 91 tmp = min( tmp , dp[i][g][h]+(h?1:0) ); 92 } 93 ret += tmp; 94 } 95 return ret-2; 96 } 97 98 int main(){ 99 int tt = 0; 100 while ( ~scanf("%s", str ) ){ 101 memset( num , 0 , sizeof(num) ); 102 ecnt = 0; 103 memset( mat , 0 , sizeof(mat) ); 104 n = 0; 105 memset( mm , -1 , sizeof(mm) ); 106 tol[0] = tol[1] = 0; 107 108 do{ 109 int g,h; 110 if ( islower(str[0] ) ) g = id(str[0]); 111 else g = str[0]<='M'?-1:-2; 112 if ( islower(str[1] ) ) h = id(str[1]); 113 else h = str[1]<='M'?-1:-2; 114 if ( g >= 0 && h >= 0 ) link(g,h),link(h,g); 115 else if ( h < 0 ) num[g][h+2]++; 116 else if ( g < 0 ) num[h][g+2]++; 117 scanf("%s", str ); 118 } while ( str[0] != '0' ); 119 printf("Case %d: ", ++tt ); 120 121 if ( n == 1 && num[0][0]>0 && num[0][1]>0 ) { 122 printf("impossible\n"); 123 continue; 124 } 125 Rep(i,n) tol[0] += num[i][0], tol[1] += num[i][1]; 126 bool ha = false , hb = false; 127 int a = 0,b; 128 Rep(i,n){ 129 if ( num[i][0]> num[i][1] ) { kind[i] = 0; ha = true; } 130 if ( num[i][0]< num[i][1] ) { kind[i] = 1; hb = true; } 131 if ( num[i][0]==num[i][1] ) kind[i] = 2; 132 a += min(num[i][0],num[i][1]); 133 } 134 if ( tol[0] == 0 && tol[1] == 0 ) b = 0; 135 else if ( tol[0] == 0 || tol[1] == 0 ){ 136 b = 0; 137 memset(mark,false,sizeof(mark)); 138 Rep(i,n) if ( !mark[i] ) { 139 if ( dfs(i,-1) ) b ++; 140 } 141 b--; 142 } 143 else{ 144 int da = inf, db = inf; 145 Rep(i,n) da = min( da , num[i][1]-num[i][0] ); 146 Rep(i,n) db = min( db , num[i][0]-num[i][1] ); 147 if ( !ha && !hb ){ 148 b = inf; 149 Rep(i,n) if ( num[i][1]-num[i][0]==da ){ 150 Rep(j,n) if ( num[j][0]-num[j][1]==db ){ 151 if ( i == j ) continue; 152 int p = kind[i], q = kind[j]; 153 kind[i] = 0; 154 kind[j] = 1; 155 b = min(b,solve()); 156 kind[i] = p; 157 kind[j] = q; 158 } 159 } 160 } 161 else if ( !ha ){ 162 a += da; 163 b = inf; 164 Rep(i,n) if ( num[i][1]-num[i][0]==da ){ 165 int p = kind[i]; 166 kind[i] = 0; 167 b = min(b,solve()); 168 kind[i] = p; 169 } 170 } 171 else if ( !hb ){ 172 a += db; 173 b = inf; 174 Rep(i,n) if ( num[i][0]-num[i][1]==db ){ 175 int p = kind[i]; 176 kind[i] = 1; 177 b = min(b,solve()); 178 kind[i] = p; 179 } 180 } 181 else b = solve(); 182 } 183 a *= 2; 184 printf("%d %d\n" , a , b ); 185 } 186 return 0; 187 }