根据题意,一个点延伸的所有边,一定是颜色不一样的,求最小颜色数和方案。由于是二分图,最小颜色很显然是全部点的最大度数,关键就在于如何求解方案?
我们这样思考,由于存在最小颜色数是最大度数这一结论,所以,我们每次使用一个颜色后,所有度数最大的点的度数肯定会减一,不然就会得出一个错误的构造方案(与结论相反),对于每个颜色,由于同色的边肯定没有交点,所以可以看成二分图上的匹配,我们对于每个颜色,使得度数最大的所有点,全部匹配成功即可,枚举颜色,多次匹配。
但是这又会出现一个新的问题:如何保证度数最大的点全部匹配成功?
因为二分图最大匹配算法(匈牙利算法)的匹配过程是-----如果不能新增一个成功匹配,就不会改动之前匹配好的)根据这一特点,我们显然需要先对度数最大的那几个点跑一遍算法
那么是否每次枚举颜色跑最大匹配,只需要
这样对度数最大那几个点跑二分图最大匹配即可??
可是这样是错误的,必须枚举全部的点,这个也是我目前对这个题最大的疑问,实在想不出为什么错误,望大佬给予解答。
https://ac.nowcoder.com/acm/contest/view-submission?submissionId=44138824&returnHomeType=1&uid=286247699
代码里面注释部分写出了我的疑惑。
在对度数最大几个点跑完之后,还要对剩下的点跑一遍,才可以AC,其实就是可以对点根据度数sort一遍即可,还有:这题RE会报WA,坑坑坑!!!
#include <cctype>
#include <cfloat>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <algorithm>
#include <deque>
#include <fstream>
#include <functional>
#include <iomanip>
#include <iostream>
#include <istream>
#include <iterator>
#include <list>
#include <map>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <string>
#include <utility>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#define ll long long
#define pll pair<long long, long long>
#define P pair<int, int>
#define PP pair<P, P>
#define eps 1e-10
#define PI 3.1415926535898
#define It set<node>::iterator
using namespace std;
const int maxn=2050;
int cnt[maxn],Head[maxn],tot,pre[maxn],ans[maxn],Node[maxn];
bool vis[maxn],M[maxn][maxn];
struct edge {
int to,Next;
}Edge[maxn<<2];
struct test {
int from,to;
}Test[maxn];
void Add(int from, int to) {
Edge[tot]={to,Head[from]};
Head[from]=tot++;
Edge[tot]={from,Head[to]};
Head[to]=tot++;
}
bool match(int u) {
vis[u]=true;
for (int i=Head[u]; ~i; i=Edge[i].Next) {
int v=Edge[i].to;
if (vis[v]) continue;
if (M[u][v]) continue;
vis[v]=true;
if (pre[v]==-1||match(pre[v])) {
pre[v]=u;
pre[u]=v;
return true;
}
}
return false;
}
bool myfun(int a, int b) {
return cnt[a]>cnt[b];
}
int main() {
memset(Head,-1,sizeof(Head));
int n,m,Max=0;
scanf("%d%d",&n,&m);
for (int i=1; i<=m; i++) {
int u,v;
scanf("%d%d",&u,&v);
Add(u,v);
Test[i]={u,v};
cnt[u]++;
cnt[v]++;
Max=max(Max,cnt[u]);
Max=max(Max,cnt[v]);
}
for (int i=1; i<=n; i++) Node[i]=i;
printf("%d\n",Max);
for (int i=1; i<=Max; i++) {
memset(pre,-1,sizeof(pre));
sort(Node+1,Node+n+1,myfun);
for (int j=1; j<=n; j++) {
if (pre[Node[j]]==-1) {
memset(vis,false,sizeof(vis));
match(Node[j]);
}
}
for (int j=1; j<=m; j++) {
int u=Test[j].from,v=Test[j].to;
if (pre[u]==v&&pre[v]==u) {
ans[j]=i;
M[u][v]=M[v][u]=true;
cnt[u]--,cnt[v]--;
}
}
}
for (int i=1; i<=m; i++) printf("%d\n",ans[i]);
return 0;
}


京公网安备 11010502036488号