/* 状态压缩 */ #include<stdio.h> #include<string.h> #include<stdlib.h> struct ke { char name[110]; int cost,end; }k[20];//存科目信息,cost是花费的时间,end是截止时间 struct node { int time,pre,fa,b; }d[1<<15];//状态数组,其下标i表示当前做作业的情况, //i=13(1101)表示标号为0、2、3的作业已做完(1表示相应科目(从右数的位数-1时期对应科目的号码)作业完成,) int n,endd,jie[20]; int cmp(const void *a,const void *b)//按字典序排序,当罚时一样时,要选字典序小的, //这样就可以通过判断科目号码的大小,判断科目名称字典序的先后 { struct ke *c=(struct ke *)a,*d=(struct ke *)b; return strcmp(c->name,d->name); } void dp() { endd=1<<n; int i,j,l,tfa,ttime; memset(d,-1,sizeof(d)); d[0].fa=0; d[0].time=0; for(i=0;i<endd;i++)//i表示当前的状态 { for(j=0;j<n;j++) { if(i&(1<<j))//若第j科目一完成,接着寻找 continue; l=i|(1<<j);//l代表在i的基础上再完成j后的状态 ttime=d[i].time+k[j].cost;//完成j后的时间 if(ttime>k[j].end)//需要罚时 tfa=d[i].fa+ttime-k[j].end; else tfa=d[i].fa;//不会罚时 if(d[l].fa==-1)//若第一次访问 { d[l].fa=tfa; d[l].time=ttime; d[l].pre=i; d[l].b=j; } else { if(tfa<d[l].fa)//若新罚时比之前的小,更新 { d[l].fa=tfa; d[l].time=ttime; d[l].pre=i; d[l].b=j; } if(tfa==d[l].fa&&d[l].pre>i)//罚时一样,若其pre的字典序比现在的大,更新 { d[l].fa=tfa; d[l].time=ttime; d[l].pre=i; d[l].b=j; } } } } } int main() { int t,i,j; scanf("%d",&t); while(t--) { scanf("%d",&n); getchar(); for(i=0;i<n;i++) scanf("%s%d%d",k[i].name,&k[i].end,&k[i].cost); qsort(k,n,sizeof(k[0]),cmp); dp(); printf("%d\n",d[(1<<n)-1].fa); i=0; j=(1<<n)-1; while(1)//倒追科目处理的顺序 { jie[i++]=d[j].b; j=d[j].pre; if(!j) break; } i--; for(;i>=0;i--) puts(k[jie[i]].name); } return 0; }
第一次写状态压缩,代码写的有点儿复杂,还有两个别人的代码,有空学学
#include <cstdio> #include <cstring> const int Limit_Size = 16; const int Char_Size = 100 + 5; int opt[ 0xffff ], n, dl[ Limit_Size ], cost[ Limit_Size ], pi[ 0xffff ], total; char name[ Limit_Size ][ Char_Size ]; void init( ) { int i, t; scanf("%d", &n); t = ( 1 << n ) - 1; total = 0; for ( i = 0; i < n; i++ ) { scanf("%s%d%d", name[ i ], &dl[ i ], &cost[ i ]); total += cost[ i ]; } pi[ 0 ] = -1; for ( i = 1; i <= t; i++ ) opt[ i ] = -1; opt[ 0 ] = 0; } int find( int con, int sum ) { if ( opt[ con ] != -1 ) return opt[ con ]; int i, t = 1, p, ex, minc = 0xfffffff, minn; for ( i = 0; i < n; i++ ) { if ( t & con ) { p = find( con ^ t, sum - cost[ i ] ); if ( sum <= dl[ i ] ) ex = 0; else ex = sum - dl[ i ]; if ( minc == p + ex ) if ( strcmp( name[ minn ], name[ i ] ) < 0 ) minn = i; if ( minc > p + ex ) { minc = p + ex; minn = i; } } t <<= 1; } pi[ con ] = minn; return opt[ con ] = minc; } void print( ) { int p = ( 1 << n ) - 1, s[ 16 ], t = 0; printf("%d\n", find( p, total ) ); while ( p ) { s[ t++ ] = pi[ p ]; p = p ^ ( 1 << pi[ p ] ); } while ( t ) puts( name[ s[ --t ] ] ); } int main( ) { int t; scanf("%d", &t); while ( t-- ) { init( ); print( ); } return 0; }