CodeForces - 1450E Capitalism(差分约束)
題目鏈接:點擊查看
題目大意:給出一張 n 個點 m 條邊的無向圖,每個點代表一個人,每個人都有一個權值 a[ i ],每條邊代表朋友關系,規定如果兩個朋友之間,權值較小的人會嫉妒權值較大的人。每個朋友關系之間都會產生一個嫉妒關系,更具體的來說,對于 ( u , v ) 來說,要么 a[ u ] = a[ v ] + 1,要么 a[ v ] = a[ u ] + 1,輸入時已經確定了某些邊的嫉妒關系,現在問如何構造,可以使得 max( a[ i ] ) - min( a[ i ] ) 最大
題目分析:吐槽一下,有的題解只講怎么建邊,而不講為什么要這樣建邊,難道圖論最難想的部分不就是建圖部分嗎?能看到這個題目還需要去學學Floyd怎么寫,學學Floyd怎么判負環嗎?
回到正題,首先因為每條邊都會產生 +1 或 -1 的關系,所以將 a[ i ] 按照奇偶分開,不難看出原圖是一張二分圖,所以題目有解的一個必要條件就是原圖是一張二分圖
然后考慮差分約束系統的模型:(百度百科)
如果一個系統由n個變量和m個約束條件組成,形成m個形如ai-aj≤k的不等式(i,j∈[1,n],k為常數),則稱其為差分約束系統(system of difference constraints)。亦即,差分約束系統是求解關于一組變量的特殊不等式組的方法。
此處的變量對應著題目中的 n 個人,約束條件對應著 m 個朋友關系,首先需要列出不等式組,形式如此:x + y <= k ,分兩種情況討論:
對于所有 x - y <= k 的邊,在建圖時建立一條 y -> x 權值為 k 的邊即可
因為題目需要求的是差分最大值,所以跑最短路然后枚舉起點找出差分最大值即可
注意到差分約束如果有解的一個充要條件是圖中沒有負環,所以需要特判一下
代碼:
//#pragma GCC optimize(2) //#pragma GCC optimize("Ofast","inline","-ffast-math") //#pragma GCC target("avx,sse2,sse3,sse4,mmx") #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<climits> #include<queue> #include<map> #include<set> #include<sstream> #include<cassert> #include<bitset> using namespace std;typedef long long LL;typedef unsigned long long ull;const int inf=0x3f3f3f3f;const int N=210;int n,m;int maze[N][N],f[N];int find(int x) {return f[x]==x?x:f[x]=find(f[x]); }void merge(int x,int y) {int xx=find(x),yy=find(y);if(xx!=yy)f[xx]=yy; }bool check()//是否為二分圖 {for(int i=1;i<=n;i++)if(find(i)==find(i+n))return false;return true; }bool Floyd()//順便判負環 {for(int k=1;k<=n;k++)for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)maze[i][j]=min(maze[i][j],maze[i][k]+maze[k][j]);for(int i=1;i<=n;i++)if(maze[i][i]<0)return false;return true; }void init() {for(int i=1;i<=n<<1;i++)f[i]=i; }int main() { #ifndef ONLINE_JUDGE // freopen("data.ans.txt","r",stdin); // freopen("data.out.txt","w",stdout); #endif // ios::sync_with_stdio(false);scanf("%d%d",&n,&m);init();for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)maze[i][j]=i==j?0:inf;for(int i=1;i<=m;i++){int u,v,w;scanf("%d%d%d",&u,&v,&w);if(w){maze[u][v]=1;maze[v][u]=-1;}else{maze[u][v]=1;maze[v][u]=1;}merge(u,v+n);merge(v,u+n);}if(!check()||!Floyd())//不是二分圖或者有負環 return 0*puts("NO");int mmax=-inf,st;for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)if(mmax<maze[i][j]){mmax=maze[i][j];st=i;}puts("YES");printf("%d\n",mmax);for(int i=1;i<=n;i++)printf("%d ",maze[st][i]);puts("");return 0; }
?
總結
以上是生活随笔為你收集整理的CodeForces - 1450E Capitalism(差分约束)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CodeForces - 1450C2
- 下一篇: CodeForces - 466C Nu