[APIO2008]免费道路
2021-03-21 19:04
标签:find 判断 停止 api 代码 ble ret -o ++i # [APIO2008]免费道路 ### 第一反应 考虑朴素的克鲁斯卡尔算法加一个限制,先选鹅卵石路,且选到k个就停止 带来的问题: - ~~叶子节点特殊处理,都选上~~(但其实是连通性) - ~~而且你诡异的发现,tm,这个鹅卵石路可以突破最小生成树!!!~~(不仔细看题面的后果) 考虑上文中的连通性,先用水泥路跑一遍$Kruskal$,然后不连通的且用到鹅卵石路的都要选上.剩下的既然水泥路可以,那么鹅卵石路也可以代替嘛,先选鹅卵石路,选到$k$个就停止 - **关键鹅卵石边**太多啦,超过$k$个 ### 代码 ```cpp using std::sort; const int M = 100005; int n, m, k, a_cnt; struct Aha{ inline bool cmp(Aha a, Aha b){ int find(int x){ inline int read(){ int main(){ for(int i = 1; i l[i].s = read(), l[i].t = read(), l[i].val = read(); for(int i = 1; i if(!l[i].val && find(l[i].t) != find(l[i].s)){ if(k printf("no solution\n");//必须要加的边超过了k for(int i = 1; i fa[i] = i; if(k){ return 0; ~~虽然又臭又长,但完全是自己敲出来的啊~~ ### 错误 我都犯了什么错呢,这才是重点啊.在luogu交了7次在bzoj交了37次,才完全明白过来很多地方为什么不可以. 1. 不可饶恕的错误,**并查集忘记路径压缩** ##### 错误代码: ```cpp 4. bzoj为啥要求"no solution"带换行啊,以后还是长个心眼 [APIO2008]免费道路 标签:find 判断 停止 api 代码 ble ret -o ++i 原文地址:https://www.cnblogs.com/LMSH7/p/9502643.html
### 正解
emm,那么什么时候是无解呢,有这么几个情况
- **能选鹅卵石边**太少了,少于$k$个
- 此图不连通
// luogu-judger-enable-o2
#include
#include
#include
const int N = 20005;
int fa[N];
int s, t, val, flag;
}l[M], ans[M];//s,t两个端点, val路性质, flag,联通
return a.val }
return x == fa[x] ? x : fa[x] = find(fa[x]);
}//并茶几没有路径压缩的傻逼就是lmsh7
int x = 0, f = 1;
char c = getchar();
while(c ‘9‘){
if(c == ‘-‘)
f = -1;
c = getchar();
}
while(c >= ‘0‘ && c x = (x c = getchar();
}
return x * f;
}
n = read(), m = read(), k = read();
for(int i = 1; i fa[i] = i;
}
if(l[i].val){
fa[l[i].s] = find(l[i].s);
fa[l[i].t] = find(l[i].t);
if(fa[l[i].t] != fa[l[i].s]){
fa[fa[l[i].t]] = fa[l[i].s];
}
}
}
fa[fa[l[i].t]] = fa[l[i].s];
ans[++a_cnt].s = l[i].s;
ans[a_cnt].t = l[i].t;
ans[a_cnt].val = l[i].val;//加入答案
l[i].flag = 1;
k--;
}
}
return 0;
}
fa[1] = find(1);
for(int i = 2; i fa[i] = find(i);
if(fa[i] != fa[i - 1]){//不联通
printf("no solution\n");
return 0;
}
}
}
for(int i = 1; i if(l[i].flag)
fa[fa[l[i].s]] = fa[l[i].t];
}
sort(l + 1, l + 1 + m, cmp);
for(int i = 1; i if((!k && !l[i].val) || l[i].flag) continue;//是割桥或者鹅卵石路且k用完
fa[l[i].s] = find(l[i].s);
fa[l[i].t] = find(l[i].t);
if(fa[l[i].t] != fa[l[i].s]){
fa[fa[l[i].t]] = fa[l[i].s];
ans[++a_cnt].s = l[i].s;
ans[a_cnt].t = l[i].t;
ans[a_cnt].val = l[i].val;
if(!l[i].val) k--; //错误:把这个放在了外面
}
}
printf("no solution\n");
return 0;
}
for(int i = 1; i printf("%d %d %d\n", ans[i].s, ans[i].t, ans[i].val);
}
}
```
2. 第二遍最小生成树的时候把减小$k$的操作放在了外面
3. **并查集操作不熟练**,导致了判断图的连通性操作失误
for(int i = 2; i fa[i] = find(i);
if(fa[i] != fa[i - 1]){
printf("no solution\n");
return 0;
}
}
```
5. 代码写的丑,调码难炸天