floyd+状压dp模板题

hdu5418

维克多与世界
时间限制:4000/2000 MS(Java /其他)内存限制:262144/131072 K(Java /其他)
提交总数:2666接受提交:1201

问题描述
经过多年的努力,Victor终于获得了飞行员执照。为了庆祝,他打算给自己买飞机,环游世界。地球上有n个国家,编号从1到n。它们通过m个无向航班进行连接,详细地说,第i个航班将连接ui-th和vi-th国家,如果Victor飞过它,这将花费Victor的飞机加油。而且他有可能从第一国家飞往每个国家。

维克多现在在一个数字为1的国家/地区,他想知道最少需要燃料才能使他至少一次访问每个国家并最终返回第一个国家。

输入值
输入的第一行包含一个整数T,表示测试用例的数量。
在每个测试案例中,第一行都有两个整数n和m,分别表示国家/地区和航班的数量。

然后有m行,每行包含三个整数ui,vi和wi,描述了一次飞行。

1≤T≤20。

1≤n≤16。

1≤m≤100000。

1≤wi≤100。

1≤ui,vi≤n。

输出量
您的程序应打印出T行:第i行应包含一个整数,表示Victor完成行程所需的最少燃料量。

样本输入
1个
3 2
1 2 2
1 3 3

样本输出
10

#include<cstdio>
#include<cstring>
#include<algorithm>
const int INF = 1<<30 ;
 
int dp[1<<17][20];
int n,m,u,v,w,mp[20][20] ;
void floyd()
{
	//最开始只允许经过 0号顶点进行中转,接下来只允许经过0号和1号顶点进行中转......允许经过0~n-1号所有顶点进行中转,来不断动态更新任意两点之间的最短路程。即求从i号顶点到j号顶点只经过前k号点的最短路程。
    for(int e=0; e<n; e++)//用来中转的点 
    for(int i=0; i<n; i++)
    if(i!=e&&mp[i][e]!=INF)
    {
        for(int j=0; j<n; j++)
            if(mp[i][j]>mp[i][e]+mp[e][j])
              mp[i][j] = mp[i][e]+mp[e][j];
    }
}
int main()
{
 
    int T ;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d%d",&n,&m);
        for(int i=0; i<(1<<n); i++)
            for(int j=0; j<=n; j++)
              dp[i][j] = INF;
 
        for(int i=0; i<=n; i++)
        {
            for(int j=0; j<=n; j++)
                 mp[i][j] = INF;
            mp[i][i]=0;
        }
 
        while(m--)
        {
            scanf("%d%d%d",&u,&v,&w);
            u--; v--;
            if(mp[u][v]>w)
                mp[u][v]=mp[v][u]=w;
        }
        floyd();
        dp[1][0] = 0 ;
        for(int s=1; s<(1<<n); s++)//s 已经做过的城市的集合走过1 3 4->10110
        for(int i=0; i<n; i++)//i停留在i,从i走到j有n种法,也要枚举一遍
        if(dp[s][i]!=INF)
        {
            for(int j=0; j<n; j++)
             
                    dp[s|(1<<j)][j] =min(dp[s][i]+mp[i][j],dp[s|(1<<j)][j]) ;
        }
        

        int ans = INF;
        for(int i=0; i<n; i++)
            
                ans = min(dp[(1<<n)-1][i]+mp[i][0],ans) ;
        printf("%d\n",ans);
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值