您的位置:首页 > 其它

hdu 1074 Doing Homework--状态压缩

2011-08-04 15:45 405 查看
/*
状态压缩
*/
#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;
}


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  struct 作业 ini c