Codeforces Global Round 12 E - Capitalism 差分约束+二分图判环
考虑怎么处理关系为0的状况
最开始写了一个分类讨论,然后发现这俩等式是矛盾的并不在一起,遂丢进垃圾箱里
但是,其实不关心谁大谁小,只要满足abs|Ai-Aj|==1就可以
根据解绝对值不等式的知识,解得:
-1<=Ai-Aj<=1
yeah,现在有不等式了,怎么处理最大化极差的问题?看到不等式想到跑差分约束,但是选最长路还是最短路?
假设有两个点u、v满足答案,即Au==maxAi,Av==minAi,i=0、1、2、3..且Au-Av是所有情况中最大的
一个性质:Au-Av<=dist(u,v)这里的dist指的是最短路
why最短路?粗略地想一下,假如v到u有多条路径,那肯定是由短板效应决定的。
否则如果取的是最长路径,那存在某条路径凑不出这么大呀!!
但是如果是最短路的话,最长路可以加加减减的凑出短的
Au-Av<=dist(u,v) -> max(Au,Av)<=max( dist(u,v) )
考虑到n只有200,所以可以枚举起点v,跑最短路得到dist数组,其中最大的即为解,然后不断更新即可
再从另一个观点理解:因为答案肯定来自某两点,枚举起点
根据差分约束的定义,得到的dist数组就是每个点的赋值
要最大化dist,也就是求差分约束最大解,见上一篇博客,应该跑最短路
最大解跑最短路,最小解跑最长路。
以上的前提是不存在奇环,可以先用二分图染色判一下。
所以做法就是二分图染色判奇环,然后跑n遍spfa跑差分约束(虽然正解是floyed呵呵呵
#include<bits/stdc++.h> #define fastio ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0) using namespace std; typedef long long ll; const int maxn=1e5+5; int tot,n,m,l,r,k; int a[maxn]; struct lys{ int from,to,nex; ll val; }e[int(1e6)]; int head[int(1e6)]; void add(int from,int to,ll val){ tot++;e[tot].from=from;e[tot].to=to; e[tot].val=val;e[tot].nex=head[from];head[from]=tot; } int cnt[maxn]; bool vis[maxn]; ll dis[maxn]; bool spfa(int s) { for(int i=1;i<=n;i++) dis[i]=LONG_LONG_MAX,vis[i]=false,cnt[i]=0; dis[s]=0; deque<int> q; q.push_front(s); vis[s]=true; while(!q.empty()) { int u; if(rand()&1)u=q.front(),q.pop_front(); else u=q.back(),q.pop_back(); vis[u]=false; for(int i=head[u];i;i=e[i].nex) { int v=e[i].to;ll w=e[i].val; if(dis[v]>dis[u]+w) { dis[v]=dis[u]+w; if(!vis[v]) { vis[v]=true; cnt[v]++; if(cnt[v]>=n+1) return false; q.push_front(v); } } } } return true; } vector<int>g[maxn]; int col[maxn]; bool dfs(int v,int c){ if(col[v]==c) return true; else if(col[v]==3-c) return false; else { col[v]=c; for(int i=0;i<g[v].size();i++){ int to=g[v][i]; if(dfs(to,3-c)==false) return false; } return true; } } int main() { //freopen("lys.in","r",stdin); fastio; cin>>n>>m; for(int i=1;i<=m;i++){ int a,b,c; cin>>a>>b>>c; g[a].push_back(b); g[b].push_back(a); if(c==1){ // b-a>=1 b-a<=1 add(a,b,1); add(b,a,-1); } else { // equal 1>=a-b>=-1 // 1>=a-b b-a<=1 add(a,b,1); add(b,a,1); } } bool valid=dfs(1,1);// 注意初始的颜色是1 if(valid==false){ cout<<"NO";return 0; } ll ans=0,pos=0; for(int i=1;i<=n;i++){ if(spfa(i)==true){ ll maxn=0; for(int j=1;j<=n;j++){ maxn=max(maxn,dis[j]); } if(maxn==LONG_LONG_MAX) continue; if(ans<=maxn) { ans=maxn;pos=i; } } } if(pos==0){ cout<<"NO"; } else { spfa(pos); cout<<"YES"<<endl; cout<<ans<<endl; for(int i=1;i<=n;i++) cout<<dis[i]<<" "; } return 0; }