題目鏈接: https://codeforces.com/contest/1070/problem/I
題意:
給你 個城市 條路徑,你現在要把這些路徑分給一些公司(公司數量可視作無限大)使得: ① 每個公司最多有兩條路徑 ② 每個城市附近的路徑最多隻能屬於 個不同的公司。 要你給出一種每條路徑所屬公司的可行解(若無解則全部輸出0)。
做法:
不愧是2600的題目。。就算有點和邊都只有600個這樣的提示,也很難想象到網絡流應該怎麼做。
想了很久最後還是投降後學的做法。 因爲每個城市附近的路徑最多隻能屬於 個公司,所以如果一個城市 附近的路徑數量 ,那麼這個城市附近的路徑中就有 條路徑需要被合併。
怎麼體現大家都 “被合併” 這個概念呢,將所有的路徑和匯點連一條邊流量爲 ,表示一條路徑只能被合併一起(即和其他一條路徑有同樣的值)。城市向附近對應的路徑連邊流量爲 ,如果這個城市有需要被合併的路徑即 ,那麼源點向它連邊流量爲 。
跑出最大流後如果和需要連邊的數值是一樣的那麼就是存在可行解的,對於所有的點,如果它連向的邊是合法的,那麼就加入到集合中一個個標起來就好樂。
代碼
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i = (int)a;i<=(int)b;i++)
#define pb push_back
#define lson rt<<1
#define rson rt<<1|1
#define mid (l+r)/2
using namespace std;
const int maxn=1205;
const int maxm=5005;
const int MAX = 1<<26;
typedef long long ll;
typedef pair<int,int> pii;
int nex[maxm],de[maxn],to[maxm],cap[maxm],from[maxm];
int n,m,k,cnt,head[maxn],d[maxn],sp,tp,np,col[maxm];//原點,匯點
vector<int> ans;
//理論複雜度n2*m
void add(int u,int v,int c){
//printf("from = %d to = %d cap = %d\n",u,v,c);
from[cnt]=u,to[cnt]=v,cap[cnt]=c,nex[cnt]=head[u],head[u]=cnt++;
from[cnt]=v,to[cnt]=u,cap[cnt]=0,nex[cnt]=head[v],head[v]=cnt++;
}
int bfs(){
queue <int> q;
memset(d,-1,sizeof(d));
d[sp]=0;
q.push(sp);
while(!q.empty()){
int cur=q.front();
q.pop();
for(int i=head[cur];i!=-1;i=nex[i]){
int u=to[i];
if(d[u]==-1 && cap[i]>0){
d[u]=d[cur]+1;
q.push(u);
}
}
}
return d[tp] != -1;
}
int dfs(int a,int b){
int r=0;
if(a==tp)return b;
for(int i=head[a];i!=-1 && r<b;i=nex[i])
{
int u=to[i];
if(cap[i]>0 && d[u]==d[a]+1)
{
int x=min(cap[i],b-r);
x=dfs(u,x);
r+=x;
//printf("from = %d to = %d edge = %d sub = %d\n",a,u,i,x);
cap[i]-=x;
cap[i^1]+=x;
}
}
if(!r)d[a]=-2;
return r;
}
int dinic(int sp,int tp){
int total=0,t;
while(bfs()){
while(t=dfs(sp,MAX))
total+=t;
}
return total;
}
void init(){
rep(i,0,n+m+1) head[i]=-1,de[i]=0;
rep(i,1,m) col[i]=0;
cnt=0; np=0;
}
int main(){
int T; scanf("%d",&T);
while(T--){
scanf("%d%d%d",&n,&m,&k);
init();
sp=0,tp=n+m+1;
rep(i,1,m){
int x,y; scanf("%d%d",&x,&y);
de[x]++,de[y]++;
add(x,n+i,1); add(y,n+i,1); add(n+i,tp,1);
}
int flag=0,sum=0;
rep(i,1,n){
if(de[i]>2*k) flag=1;
if(de[i]>k) add(sp,i,2*(de[i]-k)),sum+=2*(de[i]-k);
}
if(flag||sum!=dinic(sp,tp)){
rep(i,1,m){
printf("0%c",i==m?'\n':' ');
}
}
else{
for(int u=1;u<=n;u++){
for(int i=head[u];~i;i=nex[i]){
if(to[i]<=m+n&&to[i]>n&&cap[i]==0) {
ans.push_back(to[i]);
}
}
}
for(int i=0;i<(int)ans.size();i+=2){
int x=ans[i]-n,y=ans[i+1]-n;
col[x]=col[y]=++np;
}
rep(i,1,m) {
if(col[i]==0) col[i]=++np;
printf("%d%c",col[i],i==m?'\n':' ');
}
ans.clear();
}
}
return 0;
}