标签:指定 srand inf read 存在 reg 操作 int --
题意:有一张\(n\)点\(m\)边的无向图,有\(k\)种颜色,你需要对每条边染上这\(k\)种颜色的其中一种,也可以不染色。需要满足以下限制。
设\(s_{i,j}\)表示以\(i\)为一端的边有多少个被染了颜色\(j\)。则\(\forall i,max_{j=1}^k s_{i,j}-min_{j=1}^k s_{i,j} \leq 2\)。
每个点有一个权值\(w_i\),每染一条\((i,j)\)的边,就会产生\(w_i +w_j\)的贡献。请输出一种合法染色方案,使得总贡献最大。
\(n \leq 100,m,k \leq 1000\)。
题解:首先,一定存在一种染色方案,使得所有边都被染色。
我们先考虑一下\(k=2\)的情况如何进行染色。考虑到如果所有节点的度数都为偶数,我们一定能够找到一条遍历了所有边的回路。因此我们可以试图将原图转化。
不难发现这样构造之后,所有点的度数都是偶数。这样,我们就DFS找到这条回路,然后按照\(1212\cdots 12\)对边进行染色即可,最后将0号节点和与其有关的边删掉就行了。不难发现这样操作过后,每个点的\(max-min \leq 1\)。
那么对于\(k>2\)的情况,我们可以先将所有边随机染色,然后不断判断每个点的染色情况是否合法。如果有不合法的,就拿出\(max\)和\(min\)对应的这两种颜色,将图中这些边重新染色即可。可以发现这样操作并不会使任何点的\(max-min\)增加。
(下面引用了大神Um_nik的复杂度证明。)
我们设$P(Coloring)= \sum_i \sum_j s_{i,j}^2 \((\)s_{i,j}$的定义见题目描述)。那么有\(0 \leq P(Coloring) \leq 2nm\)。每做一次操作,\(P(Coloring)\)是严格递减的。因此,操作次数的上界是\(2nm\)次,一次操作的复杂度是\(O(n+m)\),那么总复杂度就是\(O(nm(n+m))\)。
但由于我们对所有边进行了随机化染色,因此,对于一个度数为\(d\)的节点,它对\(P\)的期望贡献是\(d+d(d-1)/k=d^2/k+d(1-\frac{1}{k})\),可以近似看作是\(d^2/k\)。因此,期望操作次数是\(O(m)\)级别的,可以通过本题。
代码:
#include<bits/stdc++.h>
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
typedef long long ll;
#define I inline void
#define IN inline int
#define C(x,y) memset(x,y,sizeof(x))
#define STS system("pause")
template<class D>I read(D &res){
res=0;register D g=1;register char ch=getchar();
while(!isdigit(ch)){
if(ch==‘-‘)g=-1;
ch=getchar();
}
while(isdigit(ch)){
res=(res<<3)+(res<<1)+(ch^48);
ch=getchar();
}
res*=g;
}
const int INF=1e9+7;
typedef pair<int,int>pii;
vector<pii>e[110];
struct E{
int to,nt,id;
}t[20200];
#define T t[k].to
int n,m,k,x,clr,tot,v[110],vis[1010],head[110],du[110],a[1010],b[1010],c[1010],cnt[1010];
stack<int>s;
I add(int x,int y,int id){
t[++tot].to=y;t[tot].nt=head[x];head[x]=tot;t[tot].id=id;du[y]++;
}
I D_1(int x){
v[x]=1;
for(re k=head[x];k!=-1;k=t[k].nt){
if(!v[T])D_1(T);
}
}
I D_2(int x,int id){
for(re &k=head[x];k!=-1;k=t[k].nt){
if(!vis[k>>1]){
vis[k>>1]=1;
D_2(T,t[k].id);
}
}
s.emplace(id);
}
I recolor(int A,int B){
C(head,-1);tot=-1;C(v,0);C(du,0);
F(i,1,m)if(c[i]==A||c[i]==B)add(a[i],b[i],i),add(b[i],a[i],i);
F(i,1,n){
if(du[i]&1){
add(i,0,0);add(0,i,0);
if(!v[i])D_1(i);
}
}
F(i,1,n){
if(v[i]||(du[i]&1))continue;
D_1(i);
add(0,i,0);add(i,0,0);
add(0,i,0);add(i,0,0);
}
F(i,0,tot>>1)vis[i]=0;
D_2(0,0);clr=0;
while(!s.empty())c[s.top()]=(clr?A:B),s.pop(),clr^=1;
}
int main(){
srand((unsigned)time(0)+19260817);
read(n);read(m);read(k);
F(i,1,n)read(x);
F(i,1,m)read(a[i]),read(b[i]),e[a[i]].emplace_back(make_pair(b[i],i)),e[b[i]].emplace_back(make_pair(a[i],i)),c[i]=rand()%k+1;
while(1){
// cout<<"!";
re sn=1,mx,mn,px,pn;
F(i,1,n){
mx=0;px=pn=1;mn=INF;F(j,1,k)cnt[j]=0;
for(auto d:e[i])cnt[c[d.second]]++;
F(j,1,k){
if(cnt[j]>mx)mx=cnt[j],px=j;
if(cnt[j]<mn)mn=cnt[j],pn=j;
}
if(mx-mn>2)recolor(px,pn),sn=0;
}
if(sn)break;
}
F(i,1,m)printf("%d\n",c[i]);
return 0;
}
标签:指定 srand inf read 存在 reg 操作 int --
原文地址:https://www.cnblogs.com/Purple-wzy/p/13279053.html