HDU 4640 SPFA+状压DP+01背包

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4640

思路:首先把每个点是否经过状态压缩为0,1,经过为1,不经过为0,求出1~((1<<n)-1)间所有状态的一个人走时的最小时间,怎么求呢,用dp思想,dis[i][j]表示走完i状态,并且最后停在j点上所用的最小时间,把所有的点从1~n变为0~n-1,起点由原来的1变成了0,初始设置dis[1<<0][0]=0,表示走完0这个点,并且最后停在0这个位置上所化的最小时间,对于和0相连的点,比如说2和0相连,则dis[(1<<0)|(1<<2)][2]=dis[1<<0][0]+weight

最后用0,1背包求出最小多个人的

AC代码

#include <iostream>
#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline bool scan_d (T &ret) {
    char c;
    int sgn;
    if (c = getchar(), c == EOF) return 0; //EOF
    while (c != '-' && (c < '0' || c > '9') ) {
        if((c = getchar()) == EOF) return 0;
    }
    sgn = (c == '-') ? -1 : 1;
    ret = (c == '-') ? 0 : (c - '0');
    while (c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
    ret *= sgn;
    return 1;
}
template<typename T>
void print(T x) {
    static char s[33], *s1; s1 = s;
    if (!x) *s1++ = '0';
    if (x < 0) putchar('-'), x = -x;
    while(x) *s1++ = (x % 10 + '0'), x /= 10;
    while(s1-- != s) putchar(*s1);
}
template<typename T>
void println(T x) {
    print(x); putchar('\n');
}

#define N 18
#define inf 0x3f3f3f3f
vector<pair<int,int>>maps[N];
long long dis[1<<N][N];
long long dp[4][1<<N];
int vist[1<<N][N];
int n,m;
int ans;
struct node
{
    int sta;
    int root;
    node(int b,int c):sta(b),root(c){}
};

void SPFA()
{
    for(int i=1;i<(1<<n);++i)
    {
        for(int j=0;j<=n;++j)
            dis[i][j]=inf;
    }
    for(int i=1;i<4;++i)
    {
        for(int j=0;j<(1<<n);++j)
            dp[i][j]=inf;
    }
    dis[1][0]=0;
    memset(vist,0,sizeof(vist));
    node n1(1,0);
    node n2(0,0);
    int weight;
    vist[1][0]=1;
    queue<node>q;
    q.push(n1);
    while(!q.empty())
    {
        n1=q.front();
        q.pop();
        vist[n1.sta][n1.root]=0;
        for(int i=0;i<maps[n1.root].size();++i)
        {
            n2.root=maps[n1.root][i].first;
            weight=maps[n1.root][i].second;
            n2.sta=n1.sta|(1<<n2.root);
            if(dis[n2.sta][n2.root]>dis[n1.sta][n1.root]+weight)
            {
                dis[n2.sta][n2.root]=dis[n1.sta][n1.root]+weight;
                if(vist[n2.sta][n2.root]==0)
                {
                    vist[n2.sta][n2.root]=1;
                    q.push(n2);
                }
            }
        }
    }
}

int main()
{
    int t;
    int u,v,w;
    int k;
    scan_d<int>(t);
    for(int ca=1;ca<=t;++ca)
    {
        scan_d<int>(n);
        scan_d<int>(m);
        for(int i=0;i<=n;++i)
            maps[i].clear();
        for(int i=1;i<=m;++i)
        {
            scan_d(u);
            scan_d(v);
            scan_d(w);
            u--;
            v--;
            maps[u].push_back(make_pair(v,w));
            maps[v].push_back(make_pair(u,w));
        }
        ans=0;
        scan_d<int>(k);
        for(int i=1;i<=k;++i)
        {
            int x;
            scan_d<int>(x);
            x--;
            ans|=1<<x;
        }
        SPFA();
        for(int i=1;i<(1<<n);++i)
        {
            for(int j=0;(1<<j)<=i;++j)
            {
                dp[1][i]=min(dp[1][i],dis[i][j]);
            }
        }
        for(int i=2;i<=3;++i)
        {
            for(int j=1;j<(1<<n);++j)
            {
                if((j&1)==0) continue;
                for(int s1=j;s1>0;s1=((s1-1)&j))
                {
                    int temp=s1|1;
                    int s2=temp^j;
                    s2|=1;
                    dp[i][j]=min(dp[i][j],max(dp[i-1][temp],dp[1][s2]));
                }

            }
        }
        long long result=inf;
        for(int i=1;i<(1<<n);++i)
        {
            if((i&ans)==ans)
                result=min(dp[3][i],result);
        }
        if(result==inf)
            printf("Case %d: -1\n",ca);
        else
            printf("Case %d: %d\n",ca,result);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36921652/article/details/82691250