http://acm.hdu.edu.cn/showproblem.php?pid=3339    这道题关键是读懂题意,揣摩每句话的意思。
    some connected electric stations表示除0点外,其他电站都是连通的。(1)
    As for a electric station, we control them if and only if our tanks stop there表示我们的坦克必须停在那里才能说是控制了电站。(2)
    大致题意是说:有n个电站,每个电站都有一定的电量,电站之间有一定距离,我们要从0点出发去占领一些电站,使得占领的电站电量之和超过总电量的一半,求达到条件所要走的最短距离。如果可能的话,输出距离,否则输出不可能。什么时候不可能呢?我们知道电站都是连通的,只要0点与任何一个电站连通,我们就可以占领所有电站,如果0点不与任何一个电站相连,就是不可能实现,也就是说0点到任何一个电站的距离都是无穷。
    我们从0点开始派出一些坦克去占领一些电站,坦克到每个电站都有一定距离,而占领每个电站之后可以得到一定电量,距离就相当于体积,电量就相当于价值,这不是就01背包吗?01背包通常的问法是给定体积,求获得最大的价值,这里的问法是给定价值,求恰好得到或多于该价值时的最小体积。我们只要从前向后搜索,找到第一个大于该价值的体积即可。
    求0点到其他点的距离,就是最短路径问题,可以用floyd算法,也可以用d
ijkstra算法,或者SPFA算法。 
#include <iostream>
using namespace std;
const int M=101,MAX=10012;
int map[M][M];
int cost[M]; //从0点到i点的费油量
int value[M];//i点的价值
int dp[MAX];//存储cost为i时的价值
int bivalue,n,m;
bool visit[M];
void dj()
{
    int i,j,temp,min;
    for(i=1;i<=n;i++)
    {
        visit[i]=false;
        cost[i]=map[0][i];
    }
    for(i=1;i<n;i++)
    {
        min=MAX;
        for(j=1;j<=n;j++)
            if(!visit[j] && cost[j]<min)
            {
                temp=j;
                min=cost[j];
            }
        if(min==MAX)
            break;
        visit[temp]=true;
        for(j=1;j<=n;j++)
            if(!visit[j] && cost[j]>cost[temp]+map[temp][j])
                cost[j]=cost[temp]+map[temp][j];
    }
}
int main()
{
    int i,j,t,c,v,d;
    bool flag;
    scanf("%d",&t);
    while(t--)
    {
        v=c=0;
        scanf("%d%d",&n,&m);
        for(i=0;i<=n;i++) //初始化为无穷
            for(j=0;j<=n;j++)
                if(i==j)
                    map[i][j]=0;
                else
                    map[i][j]=MAX;
        while(m--)
        {
            scanf("%d%d%d",&i,&j,&d);//输入注意用scanf,否则会超时
            if(d<map[i][j])        //当心陷阱,可能输入多个i,j之间的距离,我们取最小的
                map[i][j]=map[j][i]=d;
        }
        dj();
        flag=true;
        for(i=1;i<=n;i++)
        {
            scanf("%d",&value[i]);
        }
        for(i=1;i<=n;i++)
        {
            v+=value[i];
            c+=cost[i];
            if(cost[i]==MAX) //只要有一个距离是无穷,其他的也是无穷,就不可能实现
            {
                flag=false;
                break;
            }
        }
        if(flag==false)
        {
            printf("impossible\n");
            continue;
        }
        memset(dp,0,sizeof(dp));
        for(i=1;i<=n;i++)
            for(j=c;j>=cost[i];j--)
                if(dp[j-cost[i]]+value[i]>dp[j])
                    dp[j]=dp[j-cost[i]]+value[i];
        bivalue=v/2+1;
        for(i=1;i<=c;i++)   //找出恰好>半量的i
            if(dp[i]>=bivalue)
                break;
        
        printf("%d\n",i);
    }
    return 0;
}
	posted on 2011-09-16 10:48 
大大木马 阅读(223) 
评论(0)  编辑 收藏 引用