题意:
一幅有趣的图的定义为有向无自环图 它有个根 根与每个点有去边和回边 除根外每个点入度出度都是2
为了将一幅图变有趣 每次操作可以删边或加边 求 最少几次操作能使所给图变有趣
思路:
我把它当离散数学题做了半天 结果始终是WA… (想必是有一些猜想是错的…)
某位大神说他这题用匈牙利算法解的 于是得到启发
如果我把根那个点和它连着的边删掉 那么每个点就成了入度出度都为1的点 即每个点进一次出一次
说完上面那句话大家就会建图了吧 裂点建二分图求最大匹配 然后是怎么求出操作数的问题
这个问题比较难想我的理解是 操作数=加边数+删边数
加边数=满足题中有关根的加边数+(点数-匹配数)(即独立集数 因为要把图连接起来)
删边数=边数-满足题中有关根的使用的边数-匹配时使用的边数
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define M 505
#define N 1005
int maz[M][M],vis[M],match[M],edu[N],edv[N];
int n,m,ans;
bool dfs(int u)
{
int i;
for(i=1;i<=n;i++)
{
if(!vis[i]&&maz[u][i])
{
vis[i]=1;
if(!match[i]||dfs(match[i]))
{
match[i]=u;
return true;
}
}
}
return false;
}
int bimatch()
{
int i,sol=0;
memset(match,0,sizeof(match));
for(i=1;i<=n;i++)
{
memset(vis,0,sizeof(vis));
if(dfs(i)) sol++;
}
return sol;
}
int main()
{
int i,j,x,y,tmp;
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++) scanf("%d%d",&edu[i],&edv[i]);
ans=n*n;
for(i=1;i<=n;i++)
{
x=2*n-1;//add edge for root
memset(maz,0,sizeof(maz));
for(j=1;j<=m;j++)
{
if(edu[j]!=i&&edv[j]!=i) maz[edu[j]][edv[j]]=1;
else x--;
}
y=2*n-1-x;//used edge for root
ans=min(ans,n+m+x-y-2*bimatch()-1);
}
printf("%d\n",ans);
return 0;
}