VJ链接:https://vjudge.net/problem/HDU-1281
由题目描述中的“不在这些格子上放车,也可以保证尽量多的“车”被放下。”
可以联想到这句话本意即为这条路存在于在增广路中,属于“翻转”增广路之前存在的匹配。
想到了将行与列做最大匹配(一个车攻击范围为该行和该列嘛),但是没想到怎么判断“重要边”。
后来发现直接删边判断最大匹配有没有变小就可以了。。。。
匈牙利算法复杂度O(n*m),每个点都需要去寻找一次匹配,匹配过程最坏的情况就是全部边都要变,所以为n * m。
总复杂度为O((n*m)^2)(第一次尝试计算复杂度也不知道对没。。不会算复杂度还挺麻烦的。。)
代码:
#include<map>
#include<set>
#include<queue>
#include<cmath>
#include<stack>
#include<ctime>
#include<cstdio>
#include<vector>
#include<string>
#include<sstream>
#include<cstdlib>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN=1e6+10;
#define pi acos(-1.0)
#define INF 0x3f3f3f3f
#define mod 1000000009
#define endll printf("\n")
#define s1(a) scanf("%d",&a)
#define s2(a,b) scanf("%d %d",&a,&b)
#define mem(a,b) memset(a,b,sizeof(a))
#define s3(a,b,c) scanf("%d %d %d",&a,&b,&c)
int n,m,k;
int mp[111][111];
int vis[111],pei[111];
int road[MAXN<<1];
int dfs(int i)
{
for(int j=1;j<=m;j++)
{
if(mp[i][j]&&vis[j]==0)
{
vis[j]=1;
if(!pei[j]||dfs(pei[j]))
{
pei[j]=i;
return 1;
}
}
}
return 0;
}
int hungry()//
{
mem(pei,0);
int ans=0;
//求出原图的最大匹配
for(int i=1;i<=n;i++)
{
mem(vis,0);
ans+=dfs(i);
}
return ans;
}
int main()
{
int t=1;
while(~s3(n,m,k))
{
mem(mp,0);
for(int i=1,a,b;i<=k;i++)
{
s2(a,b);
mp[a][b]=1;
road[2*i-1]=a;
road[2*i]=b;
}
//
int ans=hungry();
//
int sum=0;
for(int i=1;i<=2*k;i+=2)
{
mp[road[i]][road[i+1]]=0;
int temp=hungry();
if(temp!=ans)
sum++;
mp[road[i]][road[i+1]]=1;
}
printf("Board %d have %d important blanks for %d chessmen.\n",t++,sum,ans);
}
return 0;
}
-
Swap
VJ链接:https://vjudge.net/problem/HDU-2819
问能不能通过交换,使主对角线全为一,可以发现如果满足题目条件,行和列存在一一对应关系,
和上一题相似,棋盘中某格为1表示该行与该列可以匹配。
做一次最大匹配看等不等n,输出路径方面,匈牙利算法的match数组已经记录了路径。‘
手动模拟交换过程即可(第一次遇见要输出路径的,终于理顺了点怎么输出,,,),比如,
要达到交换某两行的目的,只要交换match数组即可,如此样例中,
对于原棋盘,第1列要去第4列,第3列要去第1列,
交换1,3列之后,原本的第3列变成了第1列,那么此时棋盘中第1列不必交换(第一列匹配成功),
原本的第1列变成了第3列,此时他还是要去第4列,那么此时match[3](=4)应为原本的match[1](=4)(交换后的第三列即为原本的第一列)
match[1]同理。
#include<map>
#include<set>
#include<queue>
#include<cmath>
#include<stack>
#include<ctime>
#include<cstdio>
#include<vector>
#include<string>
#include<sstream>
#include<cstdlib>
#include<cstring>
#include<cassert>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int MAXN=1e6+10;
#define pi acos(-1.0)
#define INF 0x3f3f3f3f
#define mod 1000000009
#define endll printf("\n")
#define s1(a) scanf("%d",&a)
#define s2(a,b) scanf("%d %d",&a,&b)
#define mem(a,b) memset(a,b,sizeof(a))
#define s3(a,b,c) scanf("%d %d %d",&a,&b,&c)
int n;
int mp[111][111];
int vis[111],pei[111];
int dfs(int i)
{
for(int j=1; j<=n; j++)
{
if(mp[i][j]&&vis[j]==0)
{
vis[j]=1;
if(!pei[j]||dfs(pei[j]))
{
pei[j]=i;
return 1;
}
}
}
return 0;
}
int hungry()
{
mem(pei,0);
int ans=0;
for(int i=1; i<=n; i++)
mem(vis,0),ans+=dfs(i);
return ans;
}
int main()
{
while(~s1(n))
{
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
s1(mp[i][j]);
int ans=hungry();
if(ans!=n) printf("-1\n");
else
{
// for(int k=1; k<=n; k++)
// printf("pei[%d]=%d\n",k,pei[k]);
int num = 0,a[110], b[110];
for (int i = 1; i <= n; i++)
{
if (i == pei[i]) continue;
for (int j = 1; j <= n; j++)
{
if (i ==pei[j])
{
a[num]=i;b[num++]=j;
swap(pei[i],pei[j]);
// printf("after swap %d and %d:\n",i,j);
break;
}
}
// for(int k=1; k<=n; k++)
// printf("pei[%d]=%d\n",k,pei[k]);
}
printf("%d\n",num);
for (int i=0;i<num;i++)
printf("C %d %d\n",a[i],b[i]);
}
}
return 0;
} -
Rain on your Parade
VJ链接:https://vjudge.net/problem/HDU-2389
建图,OK,匈牙利,OK,提交,T。
匈牙利算法复杂度n*m,这里n是3000,m最大3000*3000,n*m的时间就炸掉了。。。
第一次知道还有HK算法,大概看了一下原理,以后补HK,先抄板(危险发言)。

京公网安备 11010502036488号