文化之旅

传送门

ovo这题没有靠谱的多项式复杂度的做法?!

好吧我也不知道该怎么做,于是学了一个大佬的Floyd玄学算法。

具体的实现还是很简单的,就是每次使用Floyd更新,必须要满足以下情况:

1.当前三个点文化不互相排斥

2.通往k(用于更新的点)的道路上所经过的文化与当前文化不互相排斥

3.距离更小

注意使用g[i][j][k]表示从i到j的路上排斥k文化,每次在更新的时候使用按位或来更新。

这样就可以做了……orz

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<queue>
#include<set>
#define rep(i,a,n) for(int i = a;i <= n;i++)
#define per(i,n,a) for(int i = n;i >= a;i--)
#define enter putchar('\n')

using namespace std;
typedef long long ll;
const int M = 50005;
const int INF = 10000000;

int read()
{
    int ans = 0,op = 1;
    char ch = getchar();
    while(ch < '0' || ch > '9')
    {
    if(ch == '-') op = -1;
    ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
    ans *= 10;
    ans += ch - '0';
    ch = getchar();
    }
    return ans * op;
}

int n,k,m,s,t,c[105],a[105][105],dis[105][105],u,v,d;
bool g[105][105][105];

void floyd()
{
    rep(k,1,n)
    rep(i,1,n)
    rep(j,1,n)
    {
    if(a[c[k]][c[i]] || a[c[j]][c[k]]) continue;//不符合第一种情况
    if(g[i][k][c[j]] || g[k][j][c[i]]) continue;//不符合第二种情况(注意这里不要把开始城市和结束城市搞混)
    if(dis[i][k] + dis[k][j] < dis[i][j])
    {
        rep(t,1,n) g[i][j][t] = g[i][k][t] | g[k][j][t];//枚举每一种文化并且进行更新
        g[i][j][c[k]] = 1;
        dis[i][j] = dis[i][k] + dis[k][j];//更新距离
    }
    }
}

int main()
{
    n = read(),k = read(),m = read(),s = read(),t = read();
    rep(i,1,n)
    rep(j,1,n) dis[i][j] = INF;
    rep(i,1,n) c[i] = read(),dis[i][i] = 0;
    rep(i,1,k)
    rep(j,1,k) a[i][j] = read();
    rep(i,1,m)
    {
    u = read(),v = read(),d = read();
    if(!a[c[v]][c[u]] && c[u] != c[v]) dis[u][v] = min(dis[u][v],d);
    if(!a[c[u]][c[v]] && c[u] != c[v]) dis[v][u] = min(dis[v][u],d);//只有在符合条件的时候才更新距离
    }
    rep(i,1,n)
    rep(j,1,n) g[i][j][c[i]] = 1,g[i][j][c[j]] = 1;//设置路径上的文化排斥
    floyd();
    if(dis[s][t] == INF) printf("-1\n");
    else printf("%d\n",dis[s][t]);
    return 0;
}

 

posted @ 2018-09-07 15:30  CaptainLi  阅读(169)  评论(0编辑  收藏  举报