【费用流】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 }

 

posted @ 2013-01-18 00:58  lzqxh  阅读(511)  评论(0编辑  收藏  举报