【玄学随机化】Atcoder2657/ARC078F

玄学做法。

最终的图可以看成是原图的一棵生成树 + 一些非树边,看起来不错的样子,所以考虑求留下的最大价值

考虑可以留下哪些非树边:设一条非树边的两个端点为\(\texttt{u,v}\),则\(\texttt{u->v}\)路径上的点和\(\texttt{1->n}\)路径上的点的公共点数量要\(<2\)(否则就可以走“回头路”,从而多走一条路径)

上面可以用\(\texttt{n+1}\)次dfs搞定

于是我们就只用确定生成树,一般的想法都是把生成树确定为最大生成树,然而这不一定对,怎么搞呢?

这个\(\texttt{n,m}\)都那么小,可以把最大生成树得出的结果定为\(\texttt{ans}\)的初值 ,然后随机很多生成树 调整它

生成一棵生成树就是把边集打乱,然后用krusal合并一下。

就……过了?

#include <bits/stdc++.h>
#define N 20
#define ll long long
#define lson l,mid,o<<1
#define rson mid+1,r,o<<1|1
#define Ls(o) t[o].ls
#define Rs(o) t[o].rs
#define For(i,x,y) for(int i=(x);i<=(y);++i)
#define Rof(i,x,y) for(int i=(x);i>=(y);--i)
#define Edge(x) for(int i=head[x];i;i=e[i].nxt)
#define mcpy(x,y) memcpy(x,y,sizeof(x))
#define mset(x,y) memset(x,y,sizeof(x))
using namespace std;
int ans=1e9,t,n,m,fa[N],a[N][N],_;
vector<int> g[N];
bool vis[N],use[N*N],p[N][N];
struct ed{ int u,v,w; }e[N*N],tmp[N*N];
void dfs(int x,int f){
    fa[x]=f;
    for(auto to:g[x]) if(to!=f) dfs(to,x);
}
bool cmp(const ed &x,const ed &y){ return x.w>y.w; }
void dfs2(int rt,int x,int f,int cnt){
    if(cnt<=1 && ~a[x][rt] && !p[x][rt] && !(vis[x] && vis[rt]) && f!=rt) _+=a[x][rt];
    for(auto to:g[x]) if(to!=f) dfs2(rt,to,x,cnt+vis[to]);
}
int find(int x){ return x==fa[x]?x:fa[x]=find(fa[x]); }
int solve(){
    int tot=0;_=0;
    For(i,1,n) fa[i]=i,vis[i]=0;
    For(i,1,n) For(j,1,n) p[i][j]=0;
    For(i,1,m) use[i]=0;
    For(i,1,m){
        int u=find(tmp[i].u),v=find(tmp[i].v);
        if(u==v) continue;
        if(u>v) swap(u,v);fa[v]=u;
        tot+=tmp[i].w,use[i]=1,p[tmp[i].u][tmp[i].v]=p[tmp[i].v][tmp[i].u]=1;
    }
    For(i,1,n) g[i].clear();
    For(i,1,m) if(use[i]) g[tmp[i].u].push_back(tmp[i].v),g[tmp[i].v].push_back(tmp[i].u);
    For(i,1,n) fa[i]=0;
    dfs(1,0);
    for(int i=n;i;i=fa[i]) vis[i]=1;
    For(i,1,n) dfs2(i,i,0,vis[i]);
    tot+=_/2;
    return tot;
}
void Rand(){
    random_shuffle(tmp+1,tmp+m+1);
    ans=max(ans,solve());   
}
int main(){
    int qwq=0,u,v,w;
    srand(20000000);srand(rand());srand(rand());
    scanf("%d%d",&n,&m);
    mset(a,-1);
    For(i,1,m){
        scanf("%d%d%d",&u,&v,&w);
        e[i]=(ed){u,v,w},qwq+=w,a[u][v]=a[v][u]=w;
        tmp[i]=e[i],g[u].push_back(v),g[v].push_back(u);
    }
    sort(e+1,e+m+1,cmp);
    For(i,1,m) tmp[i]=e[i];
    ans=solve();
    For(i,1,500500) Rand();
    printf("%d\n",qwq-ans);
}

猜你喜欢

转载自www.cnblogs.com/PsychicBoom/p/11624974.html