HDU 3001 Travelling

题目描述:戳这里
题解:SB状压题啊。。。
这题注意到题目中有一个条件,每一个点最多可以经过两次。这样就不能愉快地直接状压了。但是我们可以考虑一下三进制的状压DP,每个点可以经过1次或者两次。
那么直接两点之间有边就转移就可以了。
然而这题卡内存,开大一点就MLE。。。
我改了半天,又WA了。。。
最后才发现原来是-1的情况的判断没有注意到ans的大小。。。
无语。。。

#include<cstdio>
#include<string>
#include<cstring>
using namespace std;
const int maxn=20,maxm=177250;
int n,m,tot,ans;
int lnk[maxn],son[maxn*maxn],nxt[maxn*maxn],w[maxn*maxn],f[maxn][maxm],c[maxn];
int inv[maxn];
void clr(){
    tot=0; ans=1<<30;
    memset(lnk,0,sizeof(lnk));
    memset(nxt,0,sizeof(nxt));
    memset(son,0,sizeof(son));
    memset(f,63,sizeof(f));
    memset(w,0,sizeof(w));
}
void add(int x,int y,int z){
    son[++tot]=y,w[tot]=z,nxt[tot]=lnk[x],lnk[x]=tot;
}
bool make_(int x){
    memset(c,0,sizeof(c));
    for (int i=0;i<n;i++) c[i]=x%3,x/=3;
    bool check=0;
    for (int i=0;i<n;i++) if (!c[i]) {check=1; break;}
    return (!check);
}
int make_back(int x){
    int ret=0;
    for (int i=0;i<n;i++) ret+=inv[i]*c[i];
    return f[x][ret];
}
int main(){
    inv[0]=1;
    for (int i=1;i<=12;i++) inv[i]=inv[i-1]*3;
    while (~scanf("%d %d",&n,&m)) {
        clr();
        for (int i=1;i<=m;i++) {
            int x,y,z; scanf("%d %d %d",&x,&y,&z);
            add(x,y,z); add(y,x,z);
        }
        for (int i=0;i<n;i++) f[i+1][inv[i]]=0;
        for (int j=1;j<inv[n];j++)
        for (int i=1;i<=n;i++) {
            bool check=make_(j);
            if (!c[i-1]) continue;
            if (f[i][j]==0) continue;
            c[i-1]--;
            for (int k=lnk[i];k;k=nxt[k])
            if (c[son[k]-1]) f[i][j]=min(f[i][j],make_back(son[k])+w[k]);
            if (check) ans=min(ans,f[i][j]);
        }
        if (ans>1000000000) printf("-1\n"); else printf("%d\n",ans);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值