Time:2016.08.05
Author:xiaoyimi
转载注明出处谢谢
传送门
思路:
今天模拟题T1
时间全花在这上面了
我以后要因为艹正解而暴力没打完就去吃*
n,m<=10时
直接dfs暴力就好了
n,m<=1000时
考虑化边为点
ans=Σmax(入边,出边),但是我们也不知道对于一个点x来说,哪个是入边哪个是出边
所以把x的出边(在新图中已经化成了点)在新图中互相连边,权值为原图中两边权的较大值
for (int i=first[x];i;i=e[i].next)
for(int j=first[x];j;j=e[j].next)
if (i!=j) 在新图中加边(i,j),权值为max(w[i],w[j])
添加S,T,S向1发出的边(点)连边,n发出的边(点)向T连边
跑最短路即可
显然新图中边是
m2
级别的
n<=100000 m<=200000时
考虑减少边数
对所有x的出边从小到大排序
排序后,每条边i向紧挨着比它大的边i+1连边,权值为w[i+1]-w[i],i+1向i连边,权值为0
类似于补偿流的思想
同时这些出边与其相应的入边(因为是无向图)连边,权值为该出(入)边权值
要解释起来还是有点麻烦啊……
这样的连边是2m左右?反正是m级别的数
然后跑堆优化dijsktra就可以了,SPFA会被卡(但据说SPFA水过80分?)
注意:
重构图这种东西一定不能与原图搞混!
代码:
#include<cstdio>
#include<iostream>
#include<queue>
#include<algorithm>
#define M 600003
#define LL long long
#define inf 100000000000000000LL
using namespace std;
int n,m,tot,cnt,S,T;
int first[M],First[M];
LL dis[M];
bool vis[M];
struct edge{
int point,x,y,next;
}e[M<<1];
struct node{
int P;LL D;
bool operator <(const node other)const
{
return D>other.D;
}
};
struct E
{
int X,Y,Z;
bool operator <(const E other)const
{
return Z<other.Z;
}
}a[M<<1],t[M<<1];
struct Edge{int u,v,w,next;}ee[M<<1];
priority_queue <node> q;
int read()
{
int t=0;char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9') t=(t<<1)+(t<<3)+ch-48,ch=getchar();
return t;
}
void add(int po,int x,int y)
{
e[++tot]=(edge){po,x,y,first[po]};
first[po]=tot;
}
void ADD(int x,int y,int z)
{
ee[++tot]=(Edge){x,y,z,First[x]};
First[x]=tot;
}
main()
{
n=read();m=read();
int x,y,z;
for (int i=1;i<=m;i++)
{
x=read();y=read();z=read();
a[++cnt]=(E){x,y,z};
a[++cnt]=(E){y,x,z};
add(x,cnt,cnt-1);
add(y,cnt-1,cnt);
}
tot=0;
S=cnt+1;T=cnt+2;
for (int i=1;i<=cnt;i++)
{
if (a[i].X==1) ADD(S,i,a[i].Z);
if (a[i].Y==n) ADD(i,T,a[i].Z);
}
for (int i=1;i<=n;i++)
{
int tmp=0;
for (int j=first[i];j;j=e[j].next)
t[++tmp]=(E){e[j].x,e[j].y,a[e[j].x].Z};
sort(t+1,t+tmp+1);
for (int i=1;i<=tmp;i++)
ADD(t[i].X,t[i].Y,t[i].Z);
for (int i=1;i<tmp;i++)
ADD(t[i].Y,t[i+1].Y,t[i+1].Z-t[i].Z),
ADD(t[i+1].Y,t[i].Y,0);
}
for (int i=1;i<=T;i++) dis[i]=inf;
dis[S]=0;
q.push((node){S,dis[S]});
for (;!q.empty();q.pop())
{
node x=q.top();
if (!vis[x.P])vis[x.P]=1;
else continue;
for (int i=First[x.P];i;i=ee[i].next)
if (dis[x.P]+ee[i].w<dis[ee[i].v])
dis[ee[i].v]=dis[x.P]+ee[i].w,
q.push((node){ee[i].v,dis[ee[i].v]});
}
printf("%lld",dis[T]);
}