Codeforces Global Round 12 E. Capitalism【查分约束】

Codeforces Global Round 12 E. Capitalism【查分约束】
题意: 给你n个点,m条边的无向图,现在有m个限制.每个点都有自己的属性值dis
op= =1,说明dis[u]+1=dis[v];
op= =2,说明dis[u]+1=dis[v]或dis[v]+1=dis[u];
让你最大化max(dis[1-n])-min(dis[1-n]),不满足限制条件输出NO,否则输出属性方案。

思路: 看上去很明显的查分约束,首先是把等式转换成不等式,再根据三角不等式建边跑最短路。
dis[u]-dis[v]=-1
等价:dis[u]-dis[v]<=-1&&dis[u]-dis[v]>=-1
等价:dis[u]-dis[v]<=-1&&dis[v]-dis[u]<=1;

另一个式子同理:但要注意的是,这里是或的关系,所以式子要取并集
等价:dis[u]-dis[v]<=1&&dis[v]-dis[u]<=1

不等式怎么建图呢?对于dis[u]-dis[v]<=k不妨移项看看
dis[u]<=dis[v]+k;这不就是最短路松弛条件里面的运算符反过来吗?
假如v—>u k=w(v,u),那么在跑最短路的时候,不就恰好满足条件了吗?
因此我们建立v-u权值是1的边.枚举每个点跑最短路的dis数组就是属性,
然后记得判负环表示无解,再把最后的答案带回去check一遍(可能会出现约束奇环),确保满足条件。

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=2e2+5;
const int M=2e3+5;
int dis[N][N];
vector<int>G[N];
pair<int,int>q1[M];
int n,m,st;
int main() {
    
    
    scanf("%d%d",&n,&m);
    for(int i=1; i<=n; i++) {
    
    
        for(int j=1; j<=n; j++)dis[i][j]=1e9;
        dis[i][i]=0;
    }
    for(int i=1,u,v,op; i<=m; i++) {
    
    
        scanf("%d%d%d",&u,&v,&op);
        if(op==1)dis[u][v]=1,dis[v][u]=-1;
        else dis[u][v]=1,dis[v][u]=1;
        q1[i]={
    
    u,v};
    }

    for(int j=1; j<=n; j++) {
    
    
        for(int i=1; i<=n; i++) {
    
    
            for(int k=1; k<=n; k++) {
    
    
                dis[i][k]=min(dis[i][k],dis[i][j]+dis[j][k]);
            }
            if(dis[i][i]<0)return 0*printf("NO\n");
        }
    }
    int ans=0;
    for(int i=1; i<=n; i++) {
    
    
        for(int j=1; j<=n; j++) {
    
    
            if(dis[i][j]>ans) {
    
    
                ans=dis[i][j];
                st=i;
            }
        }
    }
    for(int i=1;i<=m;i++){
    
    
        if(abs(dis[st][q1[i].first]-dis[st][q1[i].second])!=1)return 0*printf("NO\n");
    }
    printf("YES\n");
    printf("%d\n",ans);
    for(int i=1;i<=n;i++)printf("%d ",dis[st][i]);
    printf("\n");

}





猜你喜欢

转载自blog.csdn.net/qq_43653111/article/details/111033712