【费用流】codeforces132E. Bits of merry old England
http://www.codeforces.com/problemset/problem/132/E
给定两种操作A,给变量赋值, B打印某个变量,其中A操作代价为赋值数字2进制表示中1的个数,要求使用这两种操作按顺序打印n个数字,最多使用m个变量,使得总代价最小。
非常经典的一类费用流问题。其中对于每个要打印的操作我们将拆成费用流图中的三个点,我们设为Ai,Bi,Ci. Ai连向Bi,权为该数字赋值到变量代价,Bi连向Ci,权为负无穷,表示一定要执行一次该打印操作。。Ci连向Ai+1表示该变量用完之后可以回收等以后其他值使用,Ci连向Bj,数字j是下一个等于数字i的打印要求,表示改变量不进行修改留到下一次直接使用。。最后Ai连向Ai+1,权为0容量为m,用来控制这个图的割来表示最多使用m个变量。。由于用电脑绘图很丑所以就这样大概描述一下把=。=。反正就用类似这样一个图于题目要求完全等价后跑一遍费用流就是答案,
View Code
1 //By Lin 2 #include<cstdio> 3 #include<cstring> 4 #include<queue> 5 #define maxn 300 6 #define Rep(i,n) for(int i = 0; i<n; i++) 7 #define foreach(i,n) for( __typeof(n.begin()) i = n.begin(); i!=n.end(); i++) 8 #define X first 9 #define Y second 10 #define mp(x,y) make_pair(x,y) 11 using namespace std; 12 typedef pair<int,int> pii; 13 14 int ecnt; 15 struct Edge{ 16 int to,w,c,num; 17 Edge *next; 18 }*mat[maxn*3],edges[maxn*20]; 19 void link(int x,int to,int w,int c){ 20 edges[ecnt].num= ecnt; 21 edges[ecnt].to = to; 22 edges[ecnt].w = w; 23 edges[ecnt].c = c; 24 edges[ecnt].next = mat[x]; 25 mat[x] = &edges[ecnt++]; 26 27 edges[ecnt].num= ecnt; 28 edges[ecnt].to = x; 29 edges[ecnt].w = 0; 30 edges[ecnt].c = -c; 31 edges[ecnt].next = mat[to]; 32 mat[to] = &edges[ecnt++]; 33 } 34 int cal(int x){ 35 int ret = 0; 36 while ( x ) { ret += x&1; x>>=1; } 37 return ret; 38 } 39 40 int n,m,data[maxn]; 41 int source,remit,dis[maxn*3],from[maxn*3][2]; 42 bool in_que[maxn*3]; 43 queue<int> que; 44 #define inf 0x37373737 45 46 bool spfa(){ 47 memset( dis , inf , sizeof(dis) ); 48 dis[source] = 0; 49 que.push( source ); 50 while ( !que.empty() ) { 51 int i = que.front(); que.pop(); 52 in_que[i] = false; 53 for( Edge *p = mat[i]; p ; p = p->next ){ 54 int to = p->to; 55 if ( p->w == 0 ) continue; 56 if ( dis[to]>dis[i]+p->c ){ 57 dis[to] = dis[i]+p->c; 58 from[to][0] = i; 59 from[to][1] = p->num; 60 if ( !in_que[to] ){ 61 in_que[to] = true; 62 que.push(to); 63 } 64 } 65 } 66 } 67 return dis[remit] != inf; 68 } 69 70 bool mark[30]; 71 int v[maxn]; 72 vector<pii> ans; 73 int get_v(){ 74 Rep(i,m) if ( mark[i] ) { mark[i] = false; return i; } 75 } 76 77 int main(){ 78 scanf("%d%d", &n, &m ); 79 Rep(i,n) scanf("%d", &data[i] ); 80 source = 3*n , remit = 3*n+1; 81 link( source , 0 , m , 0 ); 82 link( (n-1)*3+2, remit , m , 0 ); 83 link( (n-1)*3 , remit , m , 0 ); 84 Rep(i,n) { 85 if ( i != n-1 ) { 86 link(i*3,(i+1)*3,m,0); 87 link(i*3+2,(i+1)*3,1,0); 88 } 89 link(i*3,i*3+1,1,cal(data[i])); 90 link(i*3+1,i*3+2,1,-100000); 91 int j = i+1; 92 for ( ; j<n; j++) if ( data[j] == data[i] ) break; 93 if ( j<n ){ 94 link(i*3+2,j*3+1,1,0); 95 } 96 } 97 int ff = 0; 98 while ( spfa() ){ 99 int i = remit; 100 ff += dis[remit]; 101 while ( i != source ) { 102 edges[from[i][1]].w --; 103 edges[from[i][1]^1].w ++; 104 i = from[i][0]; 105 } 106 } 107 memset( mark , true , sizeof(mark) ); 108 Rep(i,n){ 109 Edge *p; 110 for( p = mat[i*3+1]; p ; p = p->next ) 111 if ( p->to != i*3+2 && p->w == 1 ) break; 112 if ( p->to == i*3 ) { 113 v[i] = get_v(); 114 ans.push_back( mp(0,i) ); 115 } 116 else v[i] = v[p->to/3]; 117 ans.push_back( mp(1,i) ); 118 if ( i == n-1 ) continue; 119 for( p = mat[i*3+2]; p ; p = p->next ) 120 if ( p->to == (i+1)*3 ) break; 121 if ( p->w == 0 ) mark[v[i]] = true; 122 } 123 printf("%d %d\n" , (int)ans.size() , ff+(n*100000) ); 124 foreach( iter , ans ){ 125 int i = iter->Y; 126 if ( iter->X == 0 ) printf("%c=%d\n" , v[i]+'a' , data[i] ); 127 else printf("print(%c)\n" , v[i]+'a' ); 128 } 129 return 0; 130 }