将可改变的边长度先置为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 second
typedef 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 second
typedef 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 second
typedef 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 second
typedef 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;
}