根据题意,一个点延伸的所有边,一定是颜色不一样的,求最小颜色数和方案。由于是二分图,最小颜色很显然是全部点的最大度数,关键就在于如何求解方案?
我们这样思考,由于存在最小颜色数是最大度数这一结论,所以,我们每次使用一个颜色后,所有度数最大的点的度数肯定会减一,不然就会得出一个错误的构造方案(与结论相反),对于每个颜色,由于同色的边肯定没有交点,所以可以看成二分图上的匹配,我们对于每个颜色,使得度数最大的所有点,全部匹配成功即可,枚举颜色,多次匹配。
但是这又会出现一个新的问题:如何保证度数最大的点全部匹配成功?
因为二分图最大匹配算法(匈牙利算法)的匹配过程是-----如果不能新增一个成功匹配,就不会改动之前匹配好的)根据这一特点,我们显然需要先对度数最大的那几个点跑一遍算法
那么是否每次枚举颜色跑最大匹配,只需要
这样对度数最大那几个点跑二分图最大匹配即可??
可是这样是错误的,必须枚举全部的点,这个也是我目前对这个题最大的疑问,实在想不出为什么错误,望大佬给予解答。
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; }