zoukankan      html  css  js  c++  java
  • BZOJ4479 : [Jsoi2013]吃货jyy

    若$kleq 15$,那么可以设$d[i][S]$表示经过了$S$集合的边,现在位于$i$点的最短路。

    可以用Dijkstra算法在$O(n^22^k)$时间内求出。

    否则若$k>15$,那么最坏情况下,它们会形成一个团,将这$k$条边连上后,图中最多剩下$7$个连通块。

    如果知道哪些边要走,哪些边不走的话,那么只要存在欧拉回路就可以。

    也就是说,所有点的度数都是偶数,且从$1$出发可以到达$k$条边的端点。

    于是考虑DP,设$f[i][j][k]$表示考虑前$i$条边,目前连通性为$j$,每个点度数的奇偶性为$k$的最小代价。

    时间复杂度$O(n^2Bell(7)2^n)$,状态比较稀疏,可以通过。

    #include<cstdio>
    #include<queue>
    #include<vector>
    #include<algorithm>
    #include<map>
    using namespace std;
    typedef pair<int,int>P;
    typedef pair<int,P>PI;
    typedef long long ll;
    const int N=13,M=880,inf=100000000,LIM=15;
    int n,m,K,o,i,j,k,x,y,z;
    inline void up(int&a,int b){a>b?(a=b):0;}
    namespace SMALL{
    int f[N][N][2],g[N][N],d[N][1<<LIM];priority_queue<PI,vector<PI>,greater<PI> >q;
    inline void ext(int x,int y,int z){
      if(d[x][y]<=z)return;
      q.push(PI(d[x][y]=z,P(x,y)));
    }
    void solve(){
      for(i=0;i<n;i++)for(j=0;j<n;j++)f[i][j][0]=-1;
      for(i=0;i<n;i++)for(j=0;j<n;j++)g[i][j]=inf;
      for(i=0;i<K;i++){
        scanf("%d%d%d",&x,&y,&z);x--,y--;
        f[x][y][0]=f[y][x][0]=i;
        f[x][y][1]=f[y][x][1]=z;
      }
      scanf("%d",&m);
      while(m--){
        scanf("%d%d%d",&x,&y,&z);x--,y--;
        up(g[x][y],z),up(g[y][x],z);
      }
      for(i=0;i<n;i++)for(j=0;j<1<<K;j++)d[i][j]=inf;
      ext(0,0,0);
      while(!q.empty()){
        PI t=q.top();q.pop();
        x=t.second.first,y=t.second.second,z=t.first;
        if(z>d[x][y])continue;
        for(i=0;i<n;i++){
          if(~f[x][i][0])ext(i,y|(1<<f[x][i][0]),z+f[x][i][1]);
          ext(i,y,z+g[x][i]);
        }
      }
      printf("%d",d[0][(1<<K)-1]);
    }
    }
    namespace BIG{
    bool must[N];
    int a[N],h,t,e[N][N],dp[2][1<<N],g[M][N][N],ans=inf;
    int w[2][M][1<<N];
    char T,v[2][M][1<<N];
    short s[2][M][1<<N],cnt[2][M];
    ll q[M];
    map<ll,int>id;
    inline void merge(int x,int y){
      x=a[x],y=a[y];
      for(int i=0;i<n;i++)if(a[i]==x)a[i]=y;
    }
    inline ll encode(){
      int i,m=0;ll t=0;
      static int v[N];
      for(i=0;i<n;i++)v[a[i]]=-1;
      for(i=0;i<n;i++){
        if(v[a[i]]<0)v[a[i]]=m++;
        t=t<<4|v[a[i]];
      }
      return t;
    }
    inline void decode(ll f){for(int i=n-1;~i;i--)a[i]=f&15,f>>=4;}
    inline bool check(ll f){
      decode(f);
      for(int i=0;i<n;i++)if(must[i]&&a[i]!=a[0])return 0;
      return 1;
    }
    inline int ext(ll x){
      int&o=id[x];
      if(o)return o;
      q[o=++t]=x;
      return o;
    }
    inline void clr(){
      T++;
      for(int i=1;i<=t;i++)cnt[o^1][i]=0;
    }
    inline void add(int x,int y,int z){
      if(z>=inf)return;
      if(v[o^1][x][y]<T){
        v[o^1][x][y]=T;
        w[o^1][x][y]=z;
        s[o^1][x][cnt[o^1][x]++]=y;
        return;
      }
      up(w[o^1][x][y],z);
    }
    void solve(){
      for(i=0;i<n;i++)a[i]=i;
      for(i=1;i<1<<n;i++)dp[0][i]=inf;
      while(K--){
        scanf("%d%d%d",&x,&y,&z);x--,y--;
        must[x]=must[y]=1;
        merge(x,y);
        for(i=0;i<1<<n;i++)dp[o^1][i]=inf;
        for(i=0;i<1<<n;i++)if(dp[o][i]<inf){
          up(dp[o^1][i^(1<<x)^(1<<y)],dp[o][i]+z);
          up(dp[o^1][i],dp[o][i]+z+z);
        }
        o^=1;
      }
      decode(encode());
      h=1;
      ext(encode());
      while(h<=t){
        ll x=q[h];
        for(i=0;i<n;i++)for(j=0;j<n;j++){
          decode(x);
          merge(i,j);
          g[h][i][j]=ext(encode());
        }
        h++;
      }
      scanf("%d",&m);
      for(i=0;i<n;i++)for(j=0;j<n;j++)e[i][j]=inf;
      while(m--){
        scanf("%d%d%d",&x,&y,&z);x--,y--;
        if(x==y)continue;
        if(x>y)swap(x,y);
        up(e[x][y],z);
      }
      clr();
      for(i=0;i<1<<n;i++)add(1,i,dp[o][i]);
      o^=1;
      for(x=0;x<n;x++)for(y=0;y<n;y++)if(e[x][y]<inf){
        z=e[x][y];
        clr();
        for(i=1;i<=t;i++)for(j=0;j<cnt[o][i];j++){
          int S=s[o][i][j],f=w[o][i][S];
          add(i,S,f);
          add(g[i][x][y],S^(1<<x)^(1<<y),f+z);
          add(g[i][x][y],S,f+z+z);
        }
        o^=1;
      }
      for(i=1;i<=t;i++)if(check(q[i]))for(j=0;j<cnt[o][i];j++)if(!s[o][i][j])up(ans,w[o][i][0]);
      printf("%d",ans);
    }
    }
    int main(){
      scanf("%d%d",&n,&K);
      if(!K)return puts("0"),0;
      if(K<=LIM)SMALL::solve();else BIG::solve();
      return 0;
    }
    

      

  • 相关阅读:
    HDU 1863 畅通工程(Kruskal)
    HDU 1879 继续畅通工程(Kruskra)
    HDU 1102 Constructing Roads(Kruskal)
    POJ 3150 Cellular Automaton(矩阵快速幂)
    POJ 3070 Fibonacci(矩阵快速幂)
    ZOJ 1648 Circuit Board(计算几何)
    ZOJ 3498 Javabeans
    ZOJ 3490 String Successor(模拟)
    Java实现 LeetCode 749 隔离病毒(DFS嵌套)
    Java实现 LeetCode 749 隔离病毒(DFS嵌套)
  • 原文地址:https://www.cnblogs.com/clrs97/p/7461211.html
Copyright © 2011-2022 走看看