【学习笔记】BZOJ4479 吃货jyy

问题等价于,问从 1 1 1出发,经过钦定的 k k k条边的欧拉回路的最小长度。

我们考虑数据分治。

如果 k ≤ 15 k\le 15 k15,那么设 d p i , s dp_{i,s} dpi,s表示当前走到 i i i,经过的关键边集合为 s s s的最小长度。直接跑 dijkstra \text{dijkstra} dijkstra即可。复杂度 O ( n 2 n log ⁡ ( n 2 n ) ) O(n2^n\log(n2^n)) O(n2nlog(n2n))

如果 k > 15 k>15 k>15,那么考虑先把 k k k条边加进去,那么最多有 7 7 7个连通块,注意到 B e l l ( 7 ) < 1000 Bell(7)<1000 Bell(7)<1000,也就是说直接状压连通性的状态数不会很大,因此设 d p i , s , k dp_{i,s,k} dpi,s,k表示考虑前 i i i条边,连通性为 s s s,点的度数奇偶性为 k k k的最小长度 。复杂度状态比较稀疏,可以通过。

个人以为这个做法是通不过去的。。。

事实上问题可以转述为:每个点的度数为偶数,并且对于关键点都和 1 1 1联通。

那么每个点有 3 3 3种状态:和 1 1 1相连且度为奇数,和 1 1 1相连且度为偶数,以及与 1 1 1不连通。

转移时考虑从外面拉一个点进来,或者在连通块内连一条边。

可以进行若干剪枝,比如先保证连通性,再保证度数的奇偶性。

复杂度 O ( 3 n log ⁡ ( 3 n ( m + k ) ) + 3 n ( m + k ) ) O(3^n\log (3^n(m+k))+3^n(m+k)) O(3nlog(3n(m+k))+3n(m+k))嗯,现在合理多了

我是调不对代码的joker

#include<bits/stdc++.h> #define fi first #define se second #define ll long long #define pb push_back #define inf 0x3f3f3f3f using namespace std; int n,K,m,f[15]; int dp[4000000],vis[4000005],vis2[15]; priority_queue<pair<int,int>>q; vector<pair<int,int>>g[15]; struct node{ int x,y,z; }e[205],e2[205]; int get(int x,int y){ return x/f[y]%3; } void relax(int u,int x){ if(dp[u]>x){ dp[u]=x,q.push({-dp[u],u}); } } int rev(int u,int x){ if(get(u,x)==1)return u+f[x]; return u-f[x]; } bool check(int s){ for(int i=0;i<n;i++){ if(get(s,i)==1)return 0; if(get(s,i)==0&&vis2[i])return 0; } return 1; } void solve(int u){ int s=0;for(int i=0;i<n;i++){ if(get(u,i))s+=1<<i; } for(int i=0;i<n;i++){ if(!get(u,i)){ int u2=u,ok=0,ff=0;ll w2=0; for(auto v:g[i]){ if(s>>v.fi&1)w2+=v.se,u2=rev(u2,v.fi),ff^=1,ok=1; }if(ok){ relax(u2+(2-ff)*f[i],dp[u]+w2); return; } } } int ok=1;for(int i=0;i<n;i++)if(vis2[i]&&!get(u,i))ok=0; for(int i=1;i<=m;i++){ int x=e2[i].x,y=e2[i].y,z=e2[i].z; if(ok&&get(u,x)&&get(u,y)){ relax(rev(rev(u,x),y),dp[u]+z); } if(get(u,x)&&!get(u,y)){ relax(rev(u,x)+f[y],dp[u]+z); } if(get(u,y)&&!get(u,x)){ relax(rev(u,y)+f[x],dp[u]+z); } } for(int i=1;i<=K;i++){ int x=e[i].x,y=e[i].y,z=e[i].z; if(get(u,x)&&get(u,y)&&ok)relax(rev(rev(u,x),y),dp[u]+z); } } int main(){ ios::sync_with_stdio(false); cin.tie(0),cout.tie(0); cin>>n>>K; for(int i=1;i<=K;i++){ int x,y,z; cin>>x>>y>>z,x--,y--,e[i]={x,y,z},vis2[x]=vis2[y]=1,g[x].pb({y,z}),g[y].pb({x,z}); } cin>>m; for(int i=1;i<=m;i++){ int x,y,z; cin>>x>>y>>z,x--,y--,e2[i]={x,y,z}; } f[0]=1;for(int i=1;i<=n;i++)f[i]=f[i-1]*3; memset(dp,0x3f,sizeof dp),dp[2]=0; q.push({0,2}); while(q.size()){ int u=q.top().se;q.pop();if(vis[u])continue;vis[u]=1; if(check(u)){ cout<<dp[u]; return 0; }solve(u); } }

__EOF__

本文作者仰望星空的蚂蚁
本文链接https://www.cnblogs.com/cqbzly/p/17530077.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   仰望星空的蚂蚁  阅读(7)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· DeepSeek 开源周回顾「GitHub 热点速览」
历史上的今天:
2021-12-10 关于自己犯过的错误
2021-12-10 【题解】[CQOI2017] 老C的方块
点击右上角即可分享
微信分享提示