ADN公司內部共 n個員工,員工之間可能曾經由於小事有了過節,老是鬧矛盾。若員工u和員工 v有矛盾,用邊(u, v)表示,共 m個矛盾。最近,ADN公司內部愈來愈不團結,Amber決定裁人。Amber想獲得一個被裁員員的清單,使得被裁員員間的不團結率最高。不團結率定義爲被裁員員間的矛盾總數與被裁員員數的比值(不團結率=被裁員員之間的矛盾總數/被裁員員數)。node
在上圖這個例子中1, 2, 4和5,4我的中都有5對矛盾,則不團結率爲\(\frac 45\)。若是咱們添加3到這個團隊,則不團結率就降低到\(\frac 56\)。ios
輸入文件的第一行包含兩個整數n和m (1≤n≤100,0≤m≤1000),n表示公司的總人數(編號從1到n),m表示矛盾的對數。
接下來m行,每行兩個整數ai和bi(1≤ai,bi≤n,ai≠bi),描述一對矛盾,每對矛盾只會出現一次。git
輸出文件的第一行爲一個整數k(1≤k≤n),表示最不團結的團隊總人數。spa
sample input #1
5 6
1 5
5 4
4 2
2 5
1 2
3 1code
sample input #2
4 0blog
sample output #1
4ip
sample output #2
1get
Note, that in the last example any team has hardness factor of zero, and any non-empty list of people is a valid answer.input
最大密度子圖模板題。string
假設答案爲\(k\) ,則要求解的問題是:
選出一個合適的點集 \(V\) 和邊集 \(E\),令\((|E|−k∗|V|)\)取得最大值。
所謂「合適」是指知足以下限制:若選擇某條邊,則必選擇其兩端點。
建圖:
以原圖的邊做爲左側頂點,權值爲\(1\);
原圖的點做爲右側頂點,權值爲\(+k\)。
若原圖中存在邊 \((u,v)\),則新圖中添加兩條邊 \(([uv]−>u),([uv]−>v)\),轉換爲最大權閉合子圖。
#include<iostream> #include<cstring> #include<cmath> #include<algorithm> #include<cstdio> #include<iomanip> #include<cstdlib> #define MAXN 0x7fffffff #define eps 1e-9 typedef long long LL; const int N=1105; using namespace std; inline int Getint(){register int x=0,f=1;register char ch=getchar();while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}while(isdigit(ch)){x=x*10+ch-'0';ch=getchar();}return x*f;} int n,m,S,T,num; struct node{int next,to,pair;double flow;}g[N<<3]; struct Edge{int x,y;}s[N]; int h[N],cnt; void AddEdge(int x,int y,double z){ g[++cnt].to=y,g[cnt].next=h[x],h[x]=cnt,g[cnt].flow=z,g[cnt].pair=cnt+1; g[++cnt].to=x,g[cnt].next=h[y],h[y]=cnt,g[cnt].flow=0,g[cnt].pair=cnt-1; } int GAP[N],dis[N]; void Init(){ static int q[N]; fill(dis,dis+num,0),fill(GAP,GAP+num,0); int l=0,r=1;q[++l]=T,++GAP[dis[T]=1]; while(l<=r){ int x=q[l++]; for(int i=h[x];i;i=g[i].next){ int to=g[i].to; if(!dis[to])++GAP[dis[to]=dis[x]+1],q[++r]=to; } } } double Dfs(int x,double Maxf){ if(x==T||!Maxf)return Maxf; double ret=0; for(int i=h[x];i;i=g[i].next){ int to=g[i].to; if(g[i].flow&&dis[x]==dis[to]+1){ double dlt=Dfs(to,min(g[i].flow,Maxf-ret)); g[i].flow-=dlt; g[g[i].pair].flow+=dlt; ret+=dlt; if(dis[S]==num+1||ret+eps>=Maxf)return ret; } } if(!(--GAP[dis[x]]))dis[S]=num+1; else GAP[++dis[x]]++; return ret; } double SAP(){ Init(); double ans=Dfs(S,MAXN); while(dis[S]<=num)ans+=Dfs(S,MAXN); return ans; } bool Check(double mid){ fill(h,h+num,0),cnt=0; for(int i=1;i<=m;i++)AddEdge(S,i,1),AddEdge(i,s[i].x+m,MAXN),AddEdge(i,s[i].y+m,MAXN); for(int i=1;i<=n;i++)AddEdge(i+m,T,mid); return m-SAP()>0; } int ans;bool vis[N]; void Find(int x){ ans+=(x>m&&x<=m+n); vis[x]=1; for(int i=h[x];i;i=g[i].next){ int to=g[i].to; if(g[i].flow&&!vis[to])Find(to); } } int main(){ n=Getint(),m=Getint(),S=0,T=n+m+1,num=T+1; if(!m)cout<<1,exit(0); for(int i=1;i<=m;i++)s[i].x=Getint(),s[i].y=Getint(); double l=0,r=m,Eps=1.0/n/n; while(l+Eps<r){ double mid=(l+r)/2; if(Check(mid))l=mid; else r=mid; } Check(l),Find(S); cout<<ans; return 0; }