結果
| 問題 |
No.2987 Colorful University of Tree
|
| コンテスト | |
| ユーザー |
|
| 提出日時 | 2025-05-24 18:30:24 |
| 言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
| 結果 |
WA
|
| 実行時間 | - |
| コード長 | 8,756 bytes |
| コンパイル時間 | 3,007 ms |
| コンパイル使用メモリ | 213,236 KB |
| 実行使用メモリ | 41,024 KB |
| 最終ジャッジ日時 | 2025-05-24 18:30:40 |
| 合計ジャッジ時間 | 13,437 ms |
|
ジャッジサーバーID (参考情報) |
judge1 / judge3 |
(要ログイン)
| ファイルパターン | 結果 |
|---|---|
| other | WA * 33 RE * 9 |
コンパイルメッセージ
main.cpp: In function ‘int main()’:
main.cpp:49:9: warning: ignoring return value of ‘int scanf(const char*, ...)’ declared with attribute ‘warn_unused_result’ [-Wunused-result]
49 | scanf("%d",&n);
| ~~~~~^~~~~~~~~
main.cpp:53:12: warning: ignoring return value of ‘int scanf(const char*, ...)’ declared with attribute ‘warn_unused_result’ [-Wunused-result]
53 | scanf("%d",&k);
| ~~~~~^~~~~~~~~
main.cpp:57:15: warning: ignoring return value of ‘int scanf(const char*, ...)’ declared with attribute ‘warn_unused_result’ [-Wunused-result]
57 | scanf("%d",&x);
| ~~~~~^~~~~~~~~
ソースコード
#include<bits/stdc++.h>
using namespace std;
int n;
int ans;
int len[200005];
vector<pair<int,int> > D;
int sum[200005];
vector<int> need[200005];
vector<int> E[200005];
vector<int> col[200005];
int qeta[400005];
int belone[200005];
int stb[200005];
vector<pair<int,int> > G[200005];
vector<int> self[200005];
int chk[200005];
vector<int> whe[200005];
bool check(int Q){//
int tim=1;
while(tim--){
for(int i=1;i<=Q;i++)sum[i]=0,need[i].clear();
for(int i=1;i<D.size();i++)swap(D[i],D[rand()%i]);
for(int i=D.size()-1;i>=0;i--){
bool flg=false;//
for(int j=1;j<=Q;j++){
if(sum[j]+D[i].first<=Q){
sum[j]+=D[i].first;
flg=true;//
need[j].push_back(D[i].second);
belone[D[i].second]=j;
break;
}
}
if(!flg)break;//
if(!i)return true;
}
}
return false;
}
bool cmp(int a,int b){
return G[a].size()>G[b].size();
}
int nxt[200005];
int find(int x){return nxt[x]==x?x:nxt[x]=find(nxt[x]);}
int main(){
srand(time(0));
// freopen("city.in","r",stdin);
// freopen("city.out","w",stdout);
scanf("%d",&n);
ans=ceil(sqrt(2*(n-1)));
for(int i=1;i<=n;i++){
int k;
scanf("%d",&k);
len[i]=k;
int x;
for(int j=1;j<=k;j++){
scanf("%d",&x);
whe[i].push_back(x+E[x].size()*n);
E[x].push_back(i);
}
// printf("%lu\n",whe[i].size());
// return 0;
ans=max(ans,k);
D.push_back(make_pair(k,i));
}
sort(D.begin(),D.end());
while(!check(ans))ans++;
printf("%d\n",ans);
// for(int i=1;i<=n;i++){
// printf("%d ",1);
// for(int j=1;j<=len[i];j++)printf("%d ",1);
// puts("");
// }
for(int i=1;i<n;i++){//如果他自己连自己,考虑预先分配颜色给他就好了
int u=E[i][0];
int v=E[i][1];
if(belone[u]==belone[v]){
self[belone[u]].push_back(i);
continue;
}
// printf("id=%d (%d,%d) %d -> %d\n",i,u,v,belone[u],belone[v]);
G[belone[u]].push_back(make_pair(belone[v],i));
G[belone[v]].push_back(make_pair(belone[u],n+i));
}
vector<int> id;
for(int i=1;i<=ans;i++)id.push_back(i);
int tim=1;
while(tim--){
sort(id.begin(),id.end(),cmp);
// return 0;
//考虑对于每个色块,枚举一下邻接边,然后再随机枚举一个颜色,把他分配给他没出现的地方
//考虑每次选择的颜色,要求出现次数最多好了,然后分配完之后他的位置就可以随便占真是太方便了
//对于相等的就随机选
//不对,这个意思不就是,不管怎么样,都能分配出来,但是还是得按照度数排序,因为极端情况有可能需要用Q+1次,大概是这样
//然后对于每个点其实也不一定要很严格说度数怎么怎么分配,只要一个点往外分配,他自己的位置就一定会空出来,所以就没有问题
//我不应该这么早就定下那些自己指向自己的边应该怎么样选择。
for(int i=0;i<id.size();i++){
int now=id[i];
// cerr<<now<<'\n';
// printf("now=%d\n",now);
// printf("i=%d now=%d\n",i,now);
vector<int> D;
// for(int j=1;j<=ans;j++){//对于一个颜色,只要对外有一点点就统计好了
// chk[j]=false;
// }
vector<int> ruozhi;
for(int j=0;j<G[now].size();j++){
int v=G[now][j].first;
int id=G[now][j].second;
if(id>n){
if(qeta[id-n]){
ruozhi.push_back(qeta[id-n]);
chk[qeta[id-n]]=now;
}
}
else{
if(qeta[id+n]){
ruozhi.push_back(qeta[id+n]);
chk[qeta[id+n]]=now;
}
}
}
sort(ruozhi.begin(),ruozhi.end());
if(ruozhi.size())D.push_back(ruozhi[0]);
for(int i=1;i<ruozhi.size();i++){
if(ruozhi[i] xor ruozhi[i-1])D.push_back(ruozhi[i]);
}
// for(int j=1;j<=ans;j++){
// if(chk[j]){
// D.push_back(j);
// }
// }
for(int j=1;j<D.size();j++){
swap(D[j],D[rand()%j]);
}
// printf("sizD=%lu sizG=%lu\n",D.size(),G[now].size());
// if(D.size())return 0;
// puts("CLEAR!!");
for(int k=0;k<=G[now].size();k++)nxt[k]=k;
for(int j=0;j<D.size();j++){
// return 0;
int ncol=D[j];
// printf("ncol=%d\n",ncol);
int k=find(0);
while(k<G[now].size()){
int v=G[now][k].first;
int id=G[now][k].second;
if(qeta[id]){
k=find(k+1);
continue;
}
// printf("k=%d id=%d\n",k,id);
if(id>n){
if(qeta[id-n]==ncol){
k=find(k+1);
continue;
}
qeta[id]=ncol;
nxt[k]=k+1;
break;
}
else{
if(qeta[id+n]==ncol){
k=find(k+1);
continue;
}
qeta[id]=ncol;
nxt[k]=k+1;
break;
}
// if(k+1==G[now].size()){
// puts("error");
// }
}
}
// if(i==0)return 0;
D.clear();
int all=2*self[now].size();
for(int j=0;j<G[now].size();j++){
int v=G[now][j].first;
int id=G[now][j].second;
if(qeta[id])continue;
all++;
}
// printf("i=%d\n",i);
// puts("clear!");
for(int j=1;j<=ans&&D.size()<all;j++){
if(chk[j] xor now){
D.push_back(j);
}
}
assert(D.size()==all);
for(int j=1;j<D.size();j++){
swap(D[j],D[rand()%j]);
}
// printf("siz=%lu sizG=%lu sizself=%lu\n",D.size(),G[now].size(),self[]);
int stb=0;
for(int j=0;j<G[now].size();j++){
int v=G[now][j].first;
int id=G[now][j].second;
if(qeta[id])continue;
qeta[id]=D[stb++];
}
for(int j=0;j<self[now].size();j++){
int eid=self[now][j];
qeta[eid]=D[stb++];
assert(stb<D.size());
qeta[n+eid]=D[stb++];
}
// puts("clear!");
// if(now==45)return 0;
}
// puts("CLEAR!!");
for(int i=1;i<=n;i++){
// printf("i=%d siz=%lu\n",i,whe[i].size());
printf("%d ",belone[i]);
for(int j=0;j<whe[i].size();j++){
// printf("%d\n",whe[i][j]);
printf("%d ",qeta[whe[i][j]]);
}
// printf("i=%d\n",i);
puts("");
}
}
// puts("No Source!")
//考虑这样都成功了!
//现在要做的事情就是开始拆分,然后但是有问题就是,我要求一条边的两端给出的颜色不准相同
//考虑先不管这个事情,暴力分配一下颜色
//如果没有一条边链接两个一样的颜色那就很好了
//否则的话考虑进行交换,我们先把色块弄出来,然后把色块之间的边集弄出来
//考虑我先从一个色块开始搜索,直接对颜色进行标号
//然后往相邻色块走。
//当两个色块之间有多条边的时候可以轮换,我们把这样的边称为重边,重边随便给标号后就可以删除
//这也太麻烦,考虑我直接搜,往下搜的时候每条边分配一个当前颜色块没选过的颜色,下面也这么往上给?
//给边新建一个点,那么新图上的边的一条边的颜色必须相同,同时每个边点还要满足一个点不能有相同颜色的限制
//考虑把缩点之后的图建出来,那么这样的话限制就变成了不准有两条共点的边取到同种颜色
//长得有点像最大独立集。
//考虑我先分配一个点的颜色,这样子持续增量构造
//度数从大到小开始分配,然后每次随机分配颜色,这样子重复做100次
//
return 0;
}
/*
考虑相当于是把点分给 Q 个集合,使得每个集合的总度数不超过 Q,问最小的Q
极值不一定取得到,比较不权威
考虑我枚举一下这个Q,因为大概就是根号级别的,大不了多少,然后考虑怎么分能判断Q是否可行呢。
首先在根号n以上的点
尝试贪心一下,优先分大的
*/