P2323 [HNOI2006]公路修建问题
\(update\)
如果按照正确理解题意的情况下, 好多题解的代码都错的啊,但毕竟十几年前的题了,数据水了
二分
一眼二分
- 最后输出答案前一定要\(check\)一遍最优解,才能得到正确的方案
const int N=10010,M=20010;
struct Edge
{
int a,b,c;
}e1[M],e2[M];
int p[N];
PII ans[N];
int n,m,k;
int find(int x)
{
if(x != p[x]) p[x]=find(p[x]);
return p[x];
}
bool check(int mid)
{
for(int i=1;i<=n;i++) p[i]=i;
int cnt=0;
for(int i=0;i<m;i++)
{
int a=e1[i].a,b=e1[i].b,c=e1[i].c;
int pa=find(a),pb=find(b);
if(c<=mid && pa != pb)
{
p[pa]=pb;
ans[cnt++]={i+1,1};
}
}
if(cnt < k) return false;
for(int i=0;i<m;i++)
{
int a=e2[i].a,b=e2[i].b,c=e2[i].c;
int pa=find(a),pb=find(b);
if(c<=mid && pa != pb)
{
p[pa]=pb;
ans[cnt++]={i+1,2};
}
}
return cnt==n-1;
}
int main()
{
cin>>n>>k>>m;
m--;
int l=0,r=0;
for(int i=0;i<m;i++)
{
int a,b,c1,c2;
cin>>a>>b>>c1>>c2;
e1[i]={a,b,c1};
e2[i]={a,b,c2};
r=max(r,c1);
}
while(l<r)
{
int mid=l+r>>1;
if(check(mid)) r=mid;
else l=mid+1;
}
cout<<l<<endl;
check(l);
for(int i=0;i<n-1;i++) cout<<ans[i].fi<<' '<<ans[i].se<<endl;
//system("pause");
}
贪心
-
要求至少有k条一级公路,那我们就排一遍序,按照C1来排序,使用并查集来判断是否添加成功。
-
当添加了k次成功之后(注意不是前k条,是成功K条),再将剩下的元素再次排序,这次是按照C1与C2的最小值来排序的,再次使用并查集判断加边,直到所有的点都在同一个集合,那么答案自然就出来了。
const int N=10010,M=20010;
struct Node
{
int id,a,b,c1,c2;
}e[M];
int p[N];
PII ans[N];
int n,m,k;
int find(int x)
{
if(x != p[x]) p[x]=find(p[x]);
return p[x];
}
bool cmp1(Node &a,Node &b)
{
return a.c1<b.c1;
}
bool cmp2(Node &a,Node &b)
{
return min(a.c1,a.c2)<min(b.c1,b.c2);
}
int kruskal()
{
for(int i=1;i<=n;i++) p[i]=i;
sort(e,e+m,cmp1);
int res=0;
int cnt=0;
int bg=0;
for(int i=0;i<m;i++)
{
int id=e[i].id,a=e[i].a,b=e[i].b,c=e[i].c1;
int pa=find(a),pb=find(b);
if(pa != pb)
{
p[pa]=pb;
res=c;
ans[cnt++]={id,1};
if(cnt == k)
{
bg=i+1;
break;
}
}
}
sort(e+bg,e+m,cmp2);
for(int i=bg;i<m;i++)
{
int id=e[i].id,a=e[i].a,b=e[i].b,c=min(e[i].c1,e[i].c2);
int pa=find(a),pb=find(b);
if(pa != pb)
{
p[pa]=pb;
res=max(res,c);
int t=e[i].c1<e[i].c2?1:2;
ans[cnt++]={id,t};
}
}
return res;
}
int main()
{
cin>>n>>k>>m;
m--;
for(int i=0;i<m;i++)
{
int a,b,c1,c2;
cin>>a>>b>>c1>>c2;
e[i]={i+1,a,b,c1,c2};
}
int t=kruskal();
cout<<t<<endl;
sort(ans,ans+n-1);
for(int i=0;i<n-1;i++) cout<<ans[i].fi<<' '<<ans[i].se<<endl;
//system("pause");
}