CodeForces

题目链接

题目大意

  给你一个完全图,求一个长度为k的最短路径,这个路径的起点和终点都是1,其中可以有重复访问的点和边,但是不能有奇数环。

解题思路

  不能有奇数环,说明走的路线得是一个二分图,我们把整个图黑白染色,染成一个二分图之后进行dp,用dp[i][j]表示走了i条路线最终走到了j的最短路,dp的起点为dp[0][1],最后求dp[k][1]即为答案。
  但是一个图的二分图染色的方案是很多的,不可能全部枚举一遍。这就是这个题的有趣之处,因为最大n=80,k=10,所以最优解的路径中最多有9个点,那么我们染的颜色和最优解不一样的概率是(frac{511}{512}),我们给他染上10000次(就是这么暴力),那么其中最优方案不是答案的概率是(frac{511}{512} ^ {10000}),可以看到机率非常小,所以说几乎不可能失败。

代码

const int maxn = 1e2+10;
ll g[maxn][maxn], dp[maxn][maxn];
int c[maxn];
int main() {
    IOS;
    int n, m; cin >> n >> m;
    for (int i = 1; i<=n; ++i) 
        for (int j = 1; j<=n; ++j) {
            cin >> g[i][j];
        }
    int __ = 1e4;
    mt19937 rand(time(0));
    ll ans = 2e18;
    while(__--) {
        for (int i = 1; i<=n; ++i) c[i] = rand()%2;
        clr(dp, 0x3f);
        dp[0][1] = 0;
        for (int i = 1; i<=m; ++i)
            for (int j = 1; j<=n; ++j)
                for (int k = 1; k<=n; ++k)
                    if (c[j]!=c[k]) dp[i][j] = min(dp[i][j], dp[i-1][k]+g[k][j]);
        ans = min(ans, dp[m][1]);
    }
    cout << ans << endl;
    return 0;
}
原文地址:https://www.cnblogs.com/shuitiangong/p/15348350.html