1. 程式人生 > >【hdu6445】【2018ccpc網路賽1008】Search for Answer 題解

【hdu6445】【2018ccpc網路賽1008】Search for Answer 題解

題目大意

       ~~~~~~ 有一幅競賽圖(n<=200),其中一些邊未定向( s [ i

] [ j ] = 1 s[i][j]=1 s [
j ] [ i ] = 0 s[j][i]=0
表示一條邊從 i
i
j j s [ i ] [ j ] = s [ j ] [ i ] = 2 s[i][j]=s[j][i]=2 表示未定向)。現在你要把這些邊定向,使得圖的權值最大。權值用下面的演算法來計算:
在這裡插入圖片描述

題解

       ~~~~~~ 據說你們都能很順利地直接推出式子。。。果然是我太菜了嗎 QAQ

       ~~~~~~ 考慮容斥,首先先把所有四元環加一次(即 A n 4 A_n^4 ),然後把不該加的去掉。不該加的環一定存在某個點連了兩條出邊,且如果這個環是 A n s Ans 不加不減的,那麼它有且僅有一個這樣的點;如果是 A n s Ans 要減的,那麼它就會有兩個這樣的點。
       ~~~~~~ 於是我們只要列舉一個點的兩條出邊,再列舉另一個點,這樣來代表一個不該加的環,然後給 A n s Ans 減 8。如果這個環是 A n s Ans 不加不減的,那麼它剛好被全部減掉;如果這個環是 A n s Ans 要減的,那麼它就被減了兩次,剛好成為負數。於是得出了下面的式子:
A n s = A n 4 i = 1 n ( d e g [ i ] 2 ) ( n 3 ) 8 Ans=A^4_n-\sum_{i=1}^n \binom{deg[i]}{2}*(n-3)*8
       ~~~~~~ (注:牛客上面的式子是錯的)

       ~~~~~~ 於是可以發現答案只跟點的出度有關,並且 ( d e g [ i ] 2 ) \sum \binom{deg[i]}{2} 越小越好。這個可以費用流,左邊一排點表示未定向的邊,右邊兩排點表示原圖的點,右邊的 i i i i&#x27; 之間連若干條邊,表示點 i i 每次度數 +1 的費用增量(類似於動態加邊那樣,但是不用動態加邊也能過)。

程式碼

#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
using namespace std;

typedef long long LL;

const int maxn=205, maxp=20405, maxe=80205;

int n,mp[maxn][maxn],dg[maxn],sum;

int ReadDigit()
{
	char ch=getchar();
	while (ch<'0' || ch>'9') ch=getchar();
	return ch-'0';
}

int tot,go[2*maxe],val[2*maxe],Cos[2*maxe],nxt[2*maxe],f1[maxp];
void ins(int x,int y,int z,int c)
{
	go[++tot]=y;
	val[tot]=z;
	Cos[tot]=c;
	nxt[tot]=f1[x];
	f1[x]=tot;
}

LL ans;
int d[10*maxp],dis[maxp],fro[maxp][2];
bool bz[maxp];
void McMf()
{
	while (1)
	{
		memset(dis,127,sizeof(dis)), dis[0]=0;
		bz[ d[1]=0 ]=1;
		for(int i=1, j=1; i<=j; i++)
		{
			for(int p=f1[d[i]]; p; p=nxt[p]) if (val[p] && dis[d[i]]+Cos[p]<dis[go[p]])
			{
				dis[go[p]]=dis[d[i]]+Cos[p];
				fro[go[p]][0]=d[i], fro[go[p]][1]=p;
				if (!bz[go[p]])
				{
					bz[ d[++j]=go[p] ]=1;
					if (dis[d[i+1]]>dis[d[j]]) swap(d[i+1],d[j]);
				}
			}
			bz[d[i]]=0;
		}
		if (dis[sum]==2139062143) break;
		for(int i=sum; i; i=fro[i][0])
		{
			int p=fro[i][1];
			val[p]--, val[(p&1) ?p+1 :p-1 ]++;
			ans+=Cos[p];
		}
	}
}

int T;
int main()
{
	scanf("%d",&T);
	while (T--)
	{
		tot=0;
		memset(f1,0,sizeof(f1));
		
		scanf("%d",&n);
		memset(dg,0,sizeof(dg));
		fo(i,1,n)
			fo(j,1,n)
			{
				mp[i][j]=ReadDigit();
				if (mp[i][j]==1) dg[i]++;
			}
		fo(i,1,n)
		{
			ins(0,i,n+5,0), ins(i,0,0,0);
			fo(j,dg[i]+1,n-1) ins(i,n+i,1,j*(j-1)/2-(j-1)*(j-2)/2), ins(n+i,i,0,0);
		}
		sum=2*n;
		fo(i,1,n-1)
			fo(j,i+1,n) if (mp[i][j]==2)
			{
				sum++;
				ins(n+i,sum,1,0), ins(sum,n+i,0,0);
				ins(n+j,sum,1,0), ins(sum,n+j,0,0);
			}
		fo(i,2*n+1,sum) ins(i,sum+1,1,0), ins(sum+1,i,0,0);
		sum++;
		
		ans=0;
		fo(i,1,n) ans+=dg[i]*(dg[i]-1)/2;
		McMf();
		ans=(LL)n*(n-1)*(n-2)*(n-3)-ans*(n-3)*8;
		
		printf("%I64d\n",ans);
	}
}