Codeforces Round #372 (Div. 2) D. Complete The Graph 好题+图论+思维+二分
来源:互联网 发布:如何连接linux服务器 编辑:程序博客网 时间:2024/06/06 17:40
将可改变的边长度先置为1,不断用dij跑最短路,若d[t]<L,增加可改变边的权值使该条最短路长度为L。直至跑完后d[t]==L结束。
注意原本的最短路已经小于L的情况,此时,最坏可能得跑m次dij,时间复杂度O(mmlogn),2168ms。
#include <cstdio>#include <cstring>#include <queue>#include <vector>#include <set>#include <algorithm>using namespace std;#define fst first#define snd secondtypedef long long ll;typedef unsigned int uii;typedef pair<ll,int> pli;typedef pair<int,int> pii;const ll inf=1e15;const int maxn=1005;const int maxm=10005;int n,m,s,t,u,v;set<pii> st;ll w,d[maxn],L;pii fa[maxn];struct ee { int u,v,id; bool f; ll w; ee(){} ee(int u,int v,int id,bool f,ll w):u(u),v(v),id(id),f(f),w(w){}};vector<ee> vec[maxn];priority_queue<pli,vector<pli>,greater<pli> > que;void dij() { memset(fa,-1,sizeof fa); for (int i=0;i<n;++i) d[i]=inf; d[s]=0; que.push(pli(0,s)); while (!que.empty()) { pli tp=que.top(); que.pop(); int u=tp.snd; ll td=tp.fst; if (td>d[u]) continue; for (uii i=0;i<vec[u].size();++i) { int v=vec[u][i].v; ll c=vec[u][i].w; if (d[v]>d[u]+c) { d[v]=d[u]+c; fa[v]=pii(u,i); que.push(pli(d[v],v)); } } }}bool fil(int u) { while (fa[u].fst!=-1) { ee &te=vec[fa[u].fst][fa[u].snd]; if (te.f==true) { te.w+=L-d[t]; vec[te.v][te.id].w+=L-d[t]; return true; } u=fa[u].fst; } return false;}int main(){ scanf("%d%d%lld%d%d",&n,&m,&L,&s,&t); for (int i=0;i<m;++i) { scanf("%d%d%lld",&u,&v,&w); vec[u].push_back(ee(u,v,vec[v].size(),!w,max(1LL,w))); vec[v].push_back(ee(v,u,vec[u].size()-1,!w,max(1LL,w))); } while (true) { dij(); if (!(d[t]<L&&fil(t))) break; } if (d[t]!=L) puts("NO"); else { puts("YES"); for (int i=0;i<n;++i) for (uii j=0;j<vec[i].size();++j) { int u=vec[i][j].u,v=vec[i][j].v; ll w=vec[i][j].w; if (st.find(pii(min(u,v),max(u,v)))==st.end()) { printf("%d %d %lld\n",u,v,w); st.insert(pii(min(u,v),max(u,v))); } } } return 0;}
删掉不在当前 【可能的】 最短路上的可变边能使程序更快一点。见pre()函数。但若AB点间有许多可变边均在可能的最短路上,时间效率没有太高的优化,1185ms。
#include <cstdio>#include <cstring>#include <queue>#include <vector>#include <set>#include <algorithm>using namespace std;#define fst first#define snd secondtypedef long long ll;typedef unsigned int uii;typedef pair<ll,int> pli;typedef pair<int,int> pii;const ll inf=1e15;const int maxn=1005;const int maxm=10005;int n,m,s,t,u,v;set<pii> st;ll w,d[maxn],L;pii fa[maxn];struct ee { int u,v,id; bool f; ll w; ee(){} ee(int u,int v,int id,bool f,ll w):u(u),v(v),id(id),f(f),w(w){}};vector<ee> vec[maxn];priority_queue<pli,vector<pli>,greater<pli> > que;void dij() { memset(fa,-1,sizeof fa); for (int i=0;i<n;++i) d[i]=inf; d[s]=0; que.push(pli(0,s)); while (!que.empty()) { pli tp=que.top(); que.pop(); int u=tp.snd; ll td=tp.fst; if (td>d[u]) continue; for (uii i=0;i<vec[u].size();++i) { int v=vec[u][i].v; ll c=vec[u][i].w; if (d[v]>d[u]+c) { d[v]=d[u]+c; fa[v]=pii(u,i); que.push(pli(d[v],v)); } } }}bool fil(int u) { while (fa[u].fst!=-1) { ee &te=vec[fa[u].fst][fa[u].snd]; if (te.f==true) { te.w+=L-d[t]; vec[te.v][te.id].w+=L-d[t]; return true; } u=fa[u].fst; } return false;}void pre() { dij(); for (int i=0;i<n;++i) for (uii j=0;j<vec[i].size();++j) { int u=vec[i][j].u,v=vec[i][j].v; ll w=vec[i][j].w; if (vec[i][j].f&&max(d[v],d[u])!=min(d[v],d[u])+w) vec[i][j].w=inf; }}int main(){ scanf("%d%d%lld%d%d",&n,&m,&L,&s,&t); for (int i=0;i<m;++i) { scanf("%d%d%lld",&u,&v,&w); vec[u].push_back(ee(u,v,vec[v].size(),!w,max(1LL,w))); vec[v].push_back(ee(v,u,vec[u].size()-1,!w,max(1LL,w))); } pre(); while (true) { dij(); if (!(d[t]<L&&fil(t))) break; } if (d[t]!=L) puts("NO"); else { puts("YES"); for (int i=0;i<n;++i) for (uii j=0;j<vec[i].size();++j) { int u=vec[i][j].u,v=vec[i][j].v; ll w=vec[i][j].w; if (st.find(pii(min(u,v),max(u,v)))==st.end()) { printf("%d %d %lld\n",u,v,w); st.insert(pii(min(u,v),max(u,v))); } } } return 0;}
删掉不在当前选定最短路上的可变边能使程序更快上许多。因为这里最短路上最多只有n-1条边。最多跑n-1次dij,时间复杂度O(nmlogn),342ms。
#include <cstdio>#include <cstring>#include <queue>#include <vector>#include <set>#include <algorithm>using namespace std;#define fst first#define snd secondtypedef long long ll;typedef unsigned int uii;typedef pair<ll,int> pli;typedef pair<int,int> pii;const ll inf=1e15;const int maxn=1005;const int maxm=10005;int n,m,s,t,u,v,a,b;bool vis[maxn][maxn];set<pii> st;ll w,d[maxn],L;pii fa[maxn];struct ee { int u,v,id; bool f; ll w; ee(){} ee(int u,int v,int id,bool f,ll w):u(u),v(v),id(id),f(f),w(w){}};vector<ee> vec[maxn];priority_queue<pli,vector<pli>,greater<pli> > que;void dij() { memset(fa,-1,sizeof fa); for (int i=0;i<n;++i) d[i]=inf; d[s]=0; que.push(pli(0,s)); while (!que.empty()) { pli tp=que.top(); que.pop(); int u=tp.snd; ll td=tp.fst; if (td>d[u]) continue; for (uii i=0;i<vec[u].size();++i) { int v=vec[u][i].v; ll c=vec[u][i].w; if (d[v]>d[u]+c) { d[v]=d[u]+c; if (fa[v].fst!=-1) { a=fa[v].fst,b=fa[v].snd; vis[a][b]=false; vis[vec[a][b].v][vec[a][b].id]=false; } fa[v]=pii(u,i); vis[u][i]=true; vis[vec[u][i].v][vec[u][i].id]=true; que.push(pli(d[v],v)); } } }}bool fil(int u) { while (fa[u].fst!=-1) { ee &te=vec[fa[u].fst][fa[u].snd]; if (te.f==true) { te.w+=L-d[t]; vec[te.v][te.id].w+=L-d[t]; return true; } u=fa[u].fst; } return false;}void pre() { dij(); for (int i=0;i<n;++i) for (uii j=0;j<vec[i].size();++j) if (vec[i][j].f&&!vis[i][j]) vec[i][j].w=inf;}int main(){ scanf("%d%d%lld%d%d",&n,&m,&L,&s,&t); for (int i=0;i<m;++i) { scanf("%d%d%lld",&u,&v,&w); vec[u].push_back(ee(u,v,vec[v].size(),!w,max(1LL,w))); vec[v].push_back(ee(v,u,vec[u].size()-1,!w,max(1LL,w))); } pre(); while (true) { dij(); if (!(d[t]<L&&fil(t))) break; } if (d[t]!=L) puts("NO"); else { puts("YES"); for (int i=0;i<n;++i) for (uii j=0;j<vec[i].size();++j) { int u=vec[i][j].u,v=vec[i][j].v; ll w=vec[i][j].w; if (st.find(pii(min(u,v),max(u,v)))==st.end()) { printf("%d %d %lld\n",u,v,w); st.insert(pii(min(u,v),max(u,v))); } } } return 0;}
题解里说有人在比赛时写了一个二分的代码,学习了一发发现有道理。
首先二分可变边的数目p,1-p置为1,p到k置为inf。找出需要置为1的最少可变边的数目。此部分复杂度O(mlognlogm)
得到p后,二分第p条需要改成的值。此部分复杂度O(mlognlogL)
总时间复杂度O(mlogn(logL+logm)),42ms
#include <bits/stdc++.h>using namespace std;#define fst first#define snd secondtypedef long long ll;typedef pair<ll,int> pli;typedef pair<int,int> pii;typedef unsigned int uii;const int maxn=1005;const ll inf=1e15;int n,m,s,t,u,v,tot,l,r,mid,res=-1,to;ll L,w,d[maxn],tr;bool vis[maxn][maxn];vector<pli> vec[maxn];vector<pii> det;priority_queue<pli,vector<pli>,greater<pli> > que;void dij() { for (int i=0;i<n;++i) d[i]=inf; d[s]=0; que.push(pli(0LL,s)); while (!que.empty()) { int u=que.top().snd; ll td=que.top().fst; que.pop(); if (td>d[u]) continue; for (uii i=0;i<vec[u].size();++i) { int v=vec[u][i].snd; ll c=vec[u][i].fst; if (d[v]>d[u]+c) { d[v]=d[u]+c; que.push(pli(d[v],v)); } } }}bool check(int mid) { for (int i=0;i<(mid<<1);++i) vec[det[i].fst][det[i].snd].fst=1; for (uii i=mid<<1;i<det.size();++i) vec[det[i].fst][det[i].snd].fst=inf; dij(); if (d[t]>L) return false; return true;}ll c2(int mid) { if (res>=0) { vec[det[res<<1].fst][det[res<<1].snd].fst=mid; vec[det[(res<<1)|1].fst][det[(res<<1)|1].snd].fst=mid; } dij(); return d[t];}int main(){ scanf("%d%d%lld%d%d",&n,&m,&L,&s,&t); for (int i=0;i<m;++i) { scanf("%d%d%lld",&u,&v,&w); vec[u].push_back(pli(w,v)); vec[v].push_back(pli(w,u)); if (!w) { det.push_back(pii(u,vec[u].size()-1)); det.push_back(pii(v,vec[v].size()-1)); } } tot=det.size()>>1; l=0,r=tot; while (l<=r) { mid=(l+r)>>1; if (check(mid)) { res=mid; r=mid-1; } else l=mid+1; } if (res==-1) puts("NO"); else { --res; l=0,r=L; while (l<=r) { mid=(l+r)>>1; tr=c2(mid); if (tr==L) break; else if (tr<L) l=mid+1; else r=mid-1; } if (l>r) puts("NO"); else { puts("YES"); for (int i=0;i<n;++i) for (uii j=0;j<vec[i].size();++j) { to=vec[i][j].snd; if (!vis[i][to]) { vis[i][to]=vis[to][i]=true; printf("%d %d %lld\n",i,to,vec[i][j].fst); } } } } return 0;}
1 0
- Codeforces Round #372 (Div. 2) D. Complete The Graph 好题+图论+思维+二分
- Codeforces Round #372 (Div. 1) D. Complete The Graph(最短路,想法题,好题)
- Codeforces 715B & 716D Complete The Graph 【最短路】 (Codeforces Round #372 (Div. 2))
- Codeforces Round #372 (Div. 2) -- D. Complete The Graph(Dijkstra单源最短路)
- Codeforces Round #372 (Div. 2) -- D. Complete The Graph(SPFA)
- Codeforces Round #372 (Div. 2) D. Complete The Graph 图论、最短路、Dijkstra、路径、分配部分边权
- Codeforces Round #388(Div. 2)D. Leaving Auction【二分+思维】好题~
- Codeforces Round #372 Complete The Graph
- Codeforces 716D Complete The Graph【思维+最短路】
- Codeforces Round #400 (Div. 1 + Div. 2, combined) D. The Door Problem(二分染色?/2-sat,好题)
- Codeforces Round #377(Div. 2)D.Exams(二分+思维)
- Codeforces Round #426 (Div. 2)The Meaningless Game(思维+二分)
- Codeforces Round #426 (Div. 2)The Meaningless Game(思维+二分)
- Codeforces Round #426 (Div. 2)The Meaningless Game(思维+二分)
- Codeforces Round #372 (Div. 1) B. Complete The Graph 解题报告
- Codeforces Round #395(Div. 2)D. Timofey and rectangles【思维】好题!
- Codeforces Round #372 (Div. 2) B. Complete the Word
- Codeforces Round #372 (Div. 2) B. Complete the Word
- 387. First Unique Character in a String
- Java中的拦截器、过滤器、监听器
- python chr()和ord()
- hibernate配置文件XML与注解
- 安卓存储对象到本地
- Codeforces Round #372 (Div. 2) D. Complete The Graph 好题+图论+思维+二分
- Decode Ways
- Android TextView显示文字对齐
- 为什么你总是学不好Linux技术?这是我的答案。
- PDB文件详解
- Ubuntu16.04.1安装mysql的曲折过程
- C语言期末复习
- 【志银】MySQL命令总结
- 股市及虚拟币市场的几种境界