hdu4640 && hdu4281

hdu4281是多旅行商问题,hdu4640是三个旅行商,这不太影响解法,主要差别在于hdu4640要求不仅仅是每个节点访问一次,而且要每个节点只能经过一次,这样求single[state][u]的时候就不能直接枚举下一个点了,而是要根据边枚举,且下一个到达的点必影响state。

hdu4281:

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<numeric>
#include<queue>
using namespace std;
const int inf=0x3fffffff;
int path[20][20];
double x[20],y[20];
int n,m,c[20];
int dp1[1<<20];
int state[1<<20],tot;
bool ok[1<<20];
void pre()
{
    tot=0;
    int i,j,sum;
    memset(ok,false,sizeof(ok));
    for(i=0;i<(1<<n);++i)
    {
        sum=0;
        for(j=0;j<n;++j)
        {
            if(i&(1<<j))
            {
                sum+=c[j];
            }
        }
        if(sum<=m)
        {
            ok[i]=true;
            state[tot++]=i;
        }
    }
}
int solve1()     //checked
{
    int i,j;
    for(i=0;i<(1<<n);++i)
        dp1[i]=inf;
    dp1[0]=0;
    for(i=1;i<(1<<n);++i)
    {
        for(j=0;j<tot;++j)
        {
            if((i|state[j])==i)
            {
                dp1[i]=min(dp1[i],dp1[i-state[j]]+1);
            }
        }
    }
    return dp1[(1<<n)-1]==inf?-1:dp1[(1<<n)-1];
}
int single[1<<20][20],best[1<<20];
int solve2()
{
    int i,j,k,u,v;
    for(i=0;i<(1<<n);++i)
    {
        for(j=0;j<n;++j)
            single[i][j]=inf;
        best[i]=inf;
    }
    single[1][0]=0;
    for(i=1;i<(1<<n);++i)
    {
        if(ok[i])
        {
            for(j=0;j<n;++j)
            {
                if(i&(1<<j))
                {
                    best[i]=min(best[i],single[i][j]+path[j][0]);
                    for(k=0;k<n;++k)
                    {
                        if(ok[i|(1<<k)]&&((i&(1<<k))==0))
                        {
                            single[i|(1<<k)][k]=min(single[i|(1<<k)][k],single[i][j]+path[j][k]);
                        }
                    }
                }
            }
        }
    }
    for(i=0;i<(1<<n);++i)
    {
        for(j=i&(i-1);j;j=((j-1)&i))
        {
            best[i]=min(best[i],best[j]+best[(i^j)|1]);
            if(j==0)
                break;
        }
    }
    return best[(1<<n)-1];
}
int main()
{
    int i,j,k,ans1,ans2;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(i=0;i<n;++i)
        {
            scanf("%lf%lf",&x[i],&y[i]);
        }
        for(i=0;i<n;++i)
        {
            scanf("%d",&c[i]);
        }
        memset(path,0,sizeof(path));
        for(i=0;i<n;++i)
        {
            for(j=i+1;j<n;++j)
            {
                path[i][j]=path[j][i]=ceil(sqrt(pow(x[i]-x[j],2)+pow(y[i]-y[j],2)));
            }
        }
        for(k=0;k<n;++k)
        {
            for(i=0;i<n;++i)
            {
                for(j=0;j<n;++j)
                {
                    path[i][j]=min(path[i][j],path[i][k]+path[k][j]);
                }
            }
        }
        pre();
        ans1=solve1();
        if(ans1==-1)
        {
            printf("-1 -1\n");
        }
        else
        {
            ans2=solve2();
            printf("%d %d\n",ans1,ans2);
        }
    }
    return 0;
}


hdu4640:

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
using namespace std;
const int inf=0x3fffffff;
const int maxn=20;
int single[1<<maxn][20];
int dp[2][1<<maxn];
struct edge
{
    int to,w,next;
}ee[maxn*maxn*2];
int e[maxn],ecnt,n,m;
void addedge(int u,int v,int c)
{
    ee[ecnt].to=v;ee[ecnt].w=c;ee[ecnt].next=e[u];e[u]=ecnt++;
    ee[ecnt].to=u;ee[ecnt].w=c;ee[ecnt].next=e[v];e[v]=ecnt++;
}
void bfs()
{
    int u,msk1,msk2,v,i,j;
    for(msk1=0;msk1<(1<<n);++msk1)
    {
        for(u=0;u<n;++u)
        {
            single[msk1][u]=inf;
        }
    }
    queue<int> q1,q2;
    q1.push(1);q2.push(0);single[1][0]=0;
    while(!q1.empty())
    {
        msk1=q1.front();q1.pop();
        u=q2.front();q2.pop();
        for(i=e[u];i!=-1;i=ee[i].next)
        {
            v=ee[i].to;
            if(single[msk1|(1<<v)][v]>single[msk1][u]+ee[i].w)
            {
                single[msk1|(1<<v)][v]=single[msk1][u]+ee[i].w;
                q1.push(msk1|(1<<v));q2.push(v);
            }
        }
    }
    for(msk1=2;msk1<(1<<n);++msk1)
    {
        dp[0][msk1>>1]=inf;
        for(j=0;j<n;++j)
        {
            dp[0][msk1>>1]=min(dp[0][msk1>>1],single[msk1|1][j]);
        }
    }
    dp[0][0]=0;
}
int main()
{
    int t,cas=0,i,j,u,v,c,ans,tar,k,msk1,msk2;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d",&n,&m);
        memset(e,-1,sizeof(e));ecnt=0;
        while(m--)
        {
            scanf("%d%d%d",&u,&v,&c);
            u--;v--;
            addedge(u,v,c);
        }
        tar=0;
        scanf("%d",&k);
        while(k--)
        {
            scanf("%d",&u);
            u-=2;
            tar|=(1<<u);
        }
        bfs();
        n--;
        for(msk1=0;msk1<(1<<n);msk1++)
        {
            dp[1][msk1]=inf;
            for(msk2=msk1;;msk2=((msk2-1)&msk1))
            {
                if(dp[0][msk2]!=inf&&dp[0][msk1^msk2]!=inf)
                {
                    dp[1][msk1]=min(dp[1][msk1],max(dp[0][msk2],dp[0][msk1^msk2]));
                }
                if(msk2==0)
                    break;
            }
        }
        ans=inf;
        for(msk1=0;msk1<(1<<n);msk1++)
        {
            if((msk1&tar)==tar)
            {
                for(msk2=msk1;;msk2=((msk2-1)&msk1))
                {
                    ans=min(ans,max(dp[0][msk2],dp[1][msk2^msk1]));
                    if(msk2==0)
                        break;
                }
            }
        }
        if(ans==inf)
        {
            printf("Case %d: -1\n",++cas);
        }
        else
        {
            printf("Case %d: %d\n",++cas,ans);
        }
    }
    return 0;
}


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值