zoukankan      html  css  js  c++  java
  • HDU

    题意:给你n个寺庙,m个村庄,p条路,现在你要在这n+m个位置中选出若干个位置打井,每个位置打井的费用会告诉你,同时p条路也有修建费用,现在每个寺庙都住着一个和尚,问你最小的费用让这n个和尚都能喝上水。

    思路:可以对照之前做的MST题目(https://www.cnblogs.com/hua-dong/p/11164702.html)。 之前那个题是让所有点都喝上水,让后新建一个0号节点,向所有点连边,边权是打井的费用,然后跑最小生成树。   而本题是让所有寺庙有水,不关心村庄,所以应该是斯坦纳树模型。

    斯坦纳树:使得关键点连通的最小代价。  dp[i][j]代表以i为根,连通状态为j的最小代价。 不停地子集DP+dijkstra....

    #include<bits/stdc++.h>
    #define rep(i,a,b) for(int i=a;i<=b;i++)
    using namespace std;
    const int maxn=2010;
    const int inf=1e9;
    int Laxt[maxn*7],Next[maxn*7],To[maxn*7],Len[maxn*7],cnt;
    int N,M,dis[maxn][maxn],dp[maxn][maxn],vis[maxn],V;
    void add(int u,int v,int len)
    {
        Next[++cnt]=Laxt[u]; Laxt[u]=cnt; To[cnt]=v;
        Len[cnt]=len;
    }
    void SPFA()
    {
        rep(i,0,V) rep(j,0,V) dis[i][j]=inf;
        rep(i,0,V) {
            queue<int>q;
            dis[i][i]=0;
            q.push(i);
            while(!q.empty()){
                int u=q.front(); q.pop(); vis[u]=0;
                for(int j=Laxt[u];j;j=Next[j]){
                    int v=To[j];
                    if(dis[i][v]>dis[i][u]+Len[j]){
                        dis[i][v]=dis[i][u]+Len[j];
                        if(!vis[v]){vis[v]=1; q.push(v);}
                    }
                }
            }
        }
    
    }
    void solve()
    {
        rep(i,0,N)
         rep(j,0,V) dp[j][1<<i]=dis[i][j];
        rep(i,1,(1<<(N+1))-1){
            if(!((i-1)&i)) continue; //只有一位,不管,上面已经给出。
            rep(j,0,V){
                dp[j][i]=inf;
                for(int k=i;k;k=(k-1)&i)
                dp[j][i]=min(dp[j][i],dp[j][k]+dp[j][i^k]);
            }
            rep(k,0,V){
               if(dp[k][i]==inf) continue;
               rep(j,0,V)
                 dp[j][i]=min(dp[j][i],dp[k][i]+dis[k][j]);
            }
        }
    }
    int main()
    {
        int P,u,v,x;
        while(~scanf("%d%d%d",&N,&M,&P)){
            V=N+M;
            rep(i,0,V) Laxt[i]=0; cnt=0;
            rep(i,1,V){
                scanf("%d",&x);
                add(0,i,x); add(i,0,x);
            }
            rep(i,1,P){
                scanf("%d%d%d",&u,&v,&x);
                add(u,v,x); add(v,u,x);
            }
            SPFA();
            solve();
            printf("%d
    ",dp[0][(1<<(N+1))-1]);
        }
        return 0;
    }
  • 相关阅读:
    java设计模式简介
    java设计模式--单例模式
    判断整形回文数
    常用正则表达式 捕获组(分组)
    [转]十分钟搞定Vue搭建
    ActiveX界面已显示,调用方法报undefined的处理办法
    [转]纯js导出json到excel(支持chrome)
    webapi 开启gzip压缩
    webapi下载文件
    iis添加共享目录为虚拟目录
  • 原文地址:https://www.cnblogs.com/hua-dong/p/11199430.html
Copyright © 2011-2022 走看看