CF125E MST company (凸優化+MST)
阿新 • • 發佈:2019-01-01
qwq自閉的一個題
首先,我們可以把原圖中的邊,分成兩類,一類是與 相連,另一類是不與 相連。
原題就轉化成選擇 條關鍵邊的
那麼我們可以按照tree I 那個題的思路來考慮這個題。
由於是 ,所以函式滿足下凸,那麼對於這種恰好選 個的問題,我們可以直接凸優化。
一個值,然後把所有與1相連的邊都加上這個值。
通過排序的時候把同權值的與1相連的邊放到前面,那麼通過二分,就能直接得到一個上界 ,表示能選大於等於 條關建邊的最小的 。
但是要是要求方案的話,應該怎麼去做呢。
qwq有一個我不會證正確性的做法。
就是重新做一個
的過程。
貪心選邊。
如果當前已經選了
個與1相連的邊,那麼跳過後面所有與1相連的邊!
qwq但是這個東西不是很理解啊(胡亂猜了一個性質,然後A掉辣qwq)
感覺坑點也很多。。
qwq
留個坑
#include<bits/stdc++.h>
#define pb push_back
#define mk make_pair
#define ll long long
#define int long long
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 3e5+1e2;
struct Edge{
int u,v;
double w;
int tag,num;
};
Edge e[maxn];int fa[maxn];int n,m,k;int val;
int find(int x)
{
if (fa[x]!=x) fa[x]=find(fa[x]);
return fa[x];
}
bool cmp(Edge a,Edge b)
{
if(a.w==b.w) return a.tag>b.tag;
return a.w<b.w;
}
int solve()
{
for (int i=1;i<=n;i++) fa[i]=i;
sort(e+1,e+1+m,cmp);
int tot=0;
for (int i=1;i<=m;i++)
{
int f1 = find(e[i].u);
int f2 = find(e[i].v);
if (f1==f2) continue;
if (e[i].tag && tot==k) continue;
fa[f1]=fa[f2];
tot+=e[i].tag;
}
return tot;
}
vector<int> v;
signed main()
{
n=read(),m=read(),k=read();
double l = -1e10,r=1e10;
int ymh=0;
for (int i=1;i<=m;i++)
{
e[i].u=read(),e[i].v=read(),scanf("%lf",&e[i].w),e[i].num=i;
if (e[i].u==1 || e[i].v==1) e[i].tag=1;
if (e[i].tag==1) ymh++;
}
double ans=0;
while(r-l>=1e-2)
{
double mid = (l+r)/2;
for (int i=1;i<=m;i++) if(e[i].tag) e[i].w+=mid;
int tmp = solve();
if (tmp>=k) l=mid,ans=mid;
else r=mid;
for (int i=1;i<=m;i++) if (e[i].tag) e[i].w-=mid;
}
for (int i=1;i<=m;i++) if (e[i].tag) e[i].w+=ans;
for (int i=1;i<=n;i++) fa[i]=i;
sort(e+1,e+1+m,cmp);
int val=0;
for (int i=1;i<=m;i++)
{
int f1 = find(e[i].u);
int f2 = find(e[i].v);
if (f1==f2) continue;
if (e[i].tag && val==k) continue;
fa[f1]=fa[f2];
val+=e[i].tag;
v.pb(e[i].num);
}
if(val!=k || v.size()!=n-1)
{
cout<<-1;
return 0;
}
cout<<n-1<<endl;
for (int i=0;i<v.size();i++) cout<<v[i]<<" ";
return 0;
}
//final