CF1310D - Tourism 随机+DP

CF1310D - Tourism

题意

N N N个点的图,给你图的邻接矩阵 g g g,求从点 1 1 1出发经过 K K K条边途径偶数个城市回到点 1 1 1的最短距离
2 ≤ N ≤ 80 , 2 ≤ K ≤ 10 2\leq N \leq 80, 2\leq K \leq 10 2N80,2K10

题解

路径是一个环,并且是一个偶数环
二分图的充要条件就是不存在奇数环
所以我们可以把图染色成一个二分图,在二分图上跑dp就行
但是枚举二分图需要 O ( 2 N ) O(2^N) O(2N),这里会超时
所以这里随机构建二分图
然后跑一个dp,令 f [ k ] [ i ] f[k][i] f[k][i]为经过 k k k条边到达点 i i i的最短距离
c o l o r [ i ] ! = c o l o r [ j ] color[i] != color[j] color[i]!=color[j],则有转移方程 f [ k ] [ j ] = m i n ( f [ k ] [ j ] , f [ k − 1 ] [ i ] + g [ i ] [ j ] ) f[k][j]=min(f[k][j],f[k-1][i]+g[i][j]) f[k][j]=min(f[k][j],f[k1][i]+g[i][j])

代码

#include 
#define sz  sizeof
using namespace std;
typedef long long ll;
const int MAX = 1e2 + 10;

int N, K;
int c[MAX];
ll g[MAX][MAX], f[15][MAX];

int main() {
    //auto start_clock = clock();
    srand(time(0));
    scanf("%d%d", &N, &K);
    for (int i = 1; i <= N; i++)
        for (int j = 1; j <= N; j++)
            scanf("%lld", &g[i][j]);
    ll ans = 9e18;
    int T = 3000;//我是随机3000次二分图
    while (T--) {//或者运行时间小于题目时限就继续运行,即(clock() - start_clock) / CLOCKS_PER_SEC < 2.9 
        for (int i = 1; i <= N; i++) c[i] = rand() % 2;//二分图染色
        memset(f, 0x3f, sz(f));
        f[0][1] = 0;
        for (int k = 1; k <= K; k++)
            for (int i = 1; i <= N; i++)
                for (int j = 1; j <= N; j++)
                    if (c[i] != c[j])
                        f[k][j] = min(f[k][j], f[k - 1][i] + g[i][j]);
        ans = min(ans, f[K][1]);
    }
    printf("%lld\n", ans);

    return 0;
}

你可能感兴趣的:(DP,Codeforces,#,随机)