最小权路径集问题 解题题报告

最小权路径集问题

自闭了,sb斯坦纳树题没看出来,以此纪念..

\(dp_{s,i}\)表示点\(i\)联通关键点集合\(s\)的最小代价,转移显然。

\[dp_{S,i}=\min_{Q+T=S}dp_{Q,i}+dp_{T,i}\\ dp_{S,i}=\min_{E(i,j)\in G}dp_{S,j}+\mathtt {edge_{i,j}} \]

\(S\)分层,每层跑最短路即可。

最后再拿个dp合并斯坦纳森林


Code:

#include <cstdio>
#include <cctype>
#include <cstring>
#include <queue>
#include <algorithm>
using std::max;
const int SIZE=1<<21;
char ibuf[SIZE],*iS,*iT;
//#define gc() (iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,SIZE,stdin),iS==iT?EOF:*iS++):*iS++)
#define gc() getchar()
template <class T>
void read(T &x)
{
    int f=0;x=0;char c=gc();
    while(!isdigit(c)) f|=c=='-',c=gc();
    while(isdigit(c)) x=x*10+c-'0',c=gc();
    if(f) x=-x;
}
void ckmin(int &x,int y){x=x<y?x:y;}
const int inf=0x3f3f3f3f;
const int N=105;
int head[N],to[N*N],Next[N*N],edge[N*N],cnt;
void add(int u,int v,int w)
{
    to[++cnt]=v,edge[cnt]=w,Next[cnt]=head[u],head[u]=cnt;
}
int n,m,k,dp[1<<10][N],aya[1<<5];
std::queue <int> q;
void spfa(int s)
{
    while(!q.empty())
    {
        int now=q.front();
        q.pop();
        for(int i=head[now];i;i=Next[i])
        {
            int v=to[i],w=edge[i];
            if(dp[s][v]>dp[s][now]+w)
            {
                dp[s][v]=dp[s][now]+w;
                q.push(v);
            }
        }
    }
}
int main()
{
    read(n),read(m),read(k);
    for(int u,v,w,i=1;i<=m;i++)
    {
        read(u),read(v),read(w);
        add(u,v,w),add(v,u,w);
    }
    memset(dp,0x3f,sizeof dp);
    for(int i=1;i<=n;i++)
    {
        if(i<=k) dp[1<<i-1][i]=0;
        dp[0][i]=0;
    }
    for(int s=1;s<1<<k;s++)
    {
        for(int i=1;i<=n;i++)
        {
            for(int t=s;t;t=t-1&s)
                ckmin(dp[s][i],dp[t][i]+dp[s^t][i]);
            if(dp[s][i]<inf) q.push(i);
        }
        spfa(s);
        for(int i=1;i<=n;i++)
            ckmin(dp[s][0],dp[s][i]);
    }
    memset(aya,0x3f,sizeof aya);
    aya[0]=0;
    k>>=1;
    for(int s=1;s<1<<k;s++)
    {
        for(int t=s;t;t=t-1&s)
        {
            int it=0;
            for(int i=0;i<k;i++)
                if(t>>i&1)
                    it|=1<<(i<<1),it|=1<<(i<<1|1);
            ckmin(aya[s],aya[s^t]+dp[it][0]);
        }
    }
    if(aya[(1<<k)-1]==inf) puts("-1");
    else printf("%d\n",aya[(1<<k)-1]);
    return 0;
}

2019.5.23

posted @ 2019-05-23 14:17  露迭月  阅读(243)  评论(0编辑  收藏  举报