hdu 1074 Doing Homework--状态压缩

/*
	状态压缩
*/
#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;
}



 

你可能感兴趣的:(hdu 1074 Doing Homework--状态压缩)