HDU 5418题解

一見すると、この質問は、すごい、これは、私はちょうどそれを終え、問題ではないのですか?洪水の問題!それから



この問題は、実際には、小さなピット表面水です。

問題の意味

N $(見逃すことはできない)とバック$ 1 $への最短経路 - $ 1模索した後。

この質問を見る前に、私たちはこの問題を見ることができます

最短ハミルトンの道

私たちは通じ漏れないし、最終的に我々はデータの範囲を参照してください$ N-1 $に、それが直接圧力DP、列挙状態を成形することができる。この質問は、各点のために必要とされたいです。

被験者が最短に与えられているので、直接計算することができます。

#include<bits/stdc++.h>
using namespace std;
int n,a[30][30];
int f[1100000][30];
int main(){
    scanf("%d",&n);
    for(int i=0;i<n;++i){
        for(int j=0;j<n;++j){
            scanf("%d",&a[i][j]);
        }
    }
    memset(f,0x3f,sizeof(f));
    f[1][0]=0;
    for(int i=1;i<(1<<n);++i){//状态
        for(int j=0;j<n;++j){//终点
            if((i>>j)&1){
                for(int k=0;k<n;++k){//起点
                    if(((i>>k)&1)&&a[j][k]){//保证有路相通
                        f[i][j]=min(f[i][j],f[i^(1<<j)][k]+a[k][j]);//找没能达到j的
                    }
                }
            }
        }
    }   
    printf("%d",f[(1<<n)-1][n-1]);//最后在n-1
    return 0;
}

だから私たちは、それぞれの側にポイントを与えて、この質問に戻ってきて、最後には慎重に考えて、通過、そして返すために、最短やる以上でありませんか?直接の実行は再びフロイド$列挙エンドリターンが十分ではありませんか$?

それから私はのためのコードを書きました

#include<bits/stdc++.h>
using namespace std;
const int INF=1<<30;
int n,m,T,dis[20][20];
int f[(1<<20)][20];
int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d %d",&n,&m);
        if(n==1){
            printf("0\n");
            continue;
        } 
        for(int i=1;i<=n;++i){
            for(int j=1;j<=n;++j){
                if(i==j) dis[i][j]=0;
                else dis[i][j]=INF;
            }
        }
        for(int i=1;i<=m;++i){
            int x,y,z;
            scanf("%d %d %d",&x,&y,&z);
            dis[x][y]=min(dis[x][y],z);
            dis[y][x]=dis[x][y];
        }
        for(int k=1;k<=n;++k){
            for(int i=1;i<=n;++i){
                for(int j=1;j<=n;++j){
                    if(dis[i][j]>dis[i][k]+dis[k][j]) dis[i][j]=dis[i][k]+dis[k][j];
                }
            }
        }
        memset(f,0x3f,sizeof(f));
        f[1][1]=0;
           for(int i=1;i<(1<<n);++i){
               for(int j=1;j<=n;++j){
                   if((i>>(j-1))&1){
                       for(int k=1;k<=n;++k){
                           if(((i>>(k-1))&1)&&(dis[j][k]!=INF)){
                               f[i][j]=min(f[i][j],f[i^(1<<(j-1))][k]+dis[j][k]);
                           }
                       }
                   }
               }
           }
           int ans=1<<30;
           for(int i=1;i<=n;++i){
               ans=min(ans,f[(1<<n)-1][i]+dis[i][1]);
           }printf("%d\n",ans);
    }
    return 0;
}

その後RE、後の音楽教師に尋ね、問題は自己ループになることがわかりました

if(n==1){
    printf("0\n");
    continue;
}

これは、直接ではなく$裏側を来て時間がないので、$を続けるREにつながる問題の核心です。

その後、私は少しを書きました

#include<bits/stdc++.h>
using namespace std;
const int INF=1<<30;
int n,m,T,dis[20][20];
int f[(1<<20)][20];
int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d %d",&n,&m);
        for(int i=0;i<=n;++i){
            for(int j=0;j<=n;++j){
                if(i==j) dis[i][j]=0;
                else dis[i][j]=INF;
            }
        }
        for(int i=1;i<=m;++i){
            int x,y,z;
            scanf("%d %d %d",&x,&y,&z);
            dis[x][y]=min(dis[x][y],z);
            dis[y][x]=dis[x][y];
        }
        if(n==1){
            printf("0");
            continue;
        }
        for(int k=1;k<=n;++k){
            for(int i=1;i<=n;++i){
                for(int j=1;j<=n;++j){
                    if(dis[i][j]>dis[i][k]+dis[k][j]) dis[i][j]=dis[i][k]+dis[k][j];
                }
            }
        }
        memset(f,0x3f,sizeof(f));
        f[1][1]=0;
           for(int i=1;i<(1<<n);++i){
               for(int j=1;j<=n;++j){
                   if((i>>(j-1))&1){
                       for(int k=1;k<=n;++k){
                           if(((i>>(k-1))&1)&&(dis[k][j]!=INF)){
                               f[i][j]=min(f[i][j],f[i^(1<<(j-1))][k]+dis[k][j]);
                           }
                       }
                   }
               }
           }
           int ans=1<<30;
           for(int i=1;i<=n;++i){
               ans=min(ans,f[(1<<n)-1][i]+dis[i][1]);
           }printf("%d\n",ans);
    }
    return 0;
}

$和$音を聞く、私は問題を自分の解決策の後ろに見て、何の問題は、それを見て最大値が、私は変更$ $ 0x3f3f3f3fとして定義されていないという考えは、それが渡されましたか?

最大2つのエラーが表示されます$ dpとの$プロセスにつながったとの理由は同じではありません、そして最終的に私が変更しました

#include<bits/stdc++.h>
using namespace std;
const int INF=0x3f3f3f3f;
int n,m,T,dis[20][20];
int f[(1<<20)][20];
int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%d %d",&n,&m);
        for(int i=0;i<=n;++i){
            for(int j=0;j<=n;++j){
                if(i==j) dis[i][j]=0;
                else dis[i][j]=INF;
            }
        }
        for(int i=1;i<=m;++i){
            int x,y,z;
            scanf("%d %d %d",&x,&y,&z);
            dis[x][y]=min(dis[x][y],z);
            dis[y][x]=dis[x][y];
        }
        if(n==1){
            printf("0\n");
            continue;
        }
        for(int k=1;k<=n;++k){
            for(int i=1;i<=n;++i){
                for(int j=1;j<=n;++j){
                    if(dis[i][j]>dis[i][k]+dis[k][j]) dis[i][j]=dis[i][k]+dis[k][j];
                }
            }
        }
        memset(f,0x3f,sizeof(f));
        f[1][1]=0;
           for(int i=1;i<(1<<n);++i){
               for(int j=1;j<=n;++j){
                   if((i>>(j-1))&1){
                       for(int k=1;k<=n;++k){
                           if(((i>>(k-1))&1)&&(dis[k][j]!=INF)){
                               f[i][j]=min(f[i][j],f[i^(1<<(j-1))][k]+dis[k][j]);
                           }
                       }
                   }
               }
           }
           int ans=INF;
           for(int i=1;i<=n;++i){
               ans=min(ans,f[(1<<n)-1][i]+dis[i][1]);
           }printf("%d\n",ans);
    }
    return 0;
}

そして、最終的に$ AC $は、実際には、この質問自体が、難しいことではありません主に、いくつかの詳細に扱って、複数のデータセットにさらさ質問、通常多くの詳細を書くにはまだ注意を払わなければならないことは明らかです。

おすすめ

転載: www.cnblogs.com/donkey2603089141/p/11736091.html