Powered by:AB_IN 局外人
介绍
板子。先放个没注释的。
#include
using namespace std;
namespace IO{
char ibuf[1<<21],*ip=ibuf,*ip_=ibuf;
char obuf[1<<21],*op=obuf,*op_=obuf+(1<<21);
inline char gc(){
if(ip!=ip_)return *ip++;
ip=ibuf;ip_=ip+fread(ibuf,1,1<<21,stdin);
return ip==ip_?EOF:*ip++;
}
inline void pc(char c){
if(op==op_)fwrite(obuf,1,1<<21,stdout),op=obuf;
*op++=c;
}
inline int read(){
register int x=0,ch=gc(),w=1;
for(;ch<'0'||ch>'9';ch=gc())if(ch=='-')w=-1;
for(;ch>='0'&&ch<='9';ch=gc())x=x*10+ch-48;
return w*x;
}
template<class I>
inline void write(I x){
if(x<0)pc('-'),x=-x;
if(x>9)write(x/10);pc(x%10+'0');
}
class flusher_{
public:
~flusher_(){if(op!=obuf)fwrite(obuf,1,op-obuf,stdout);}
}IO_flusher;
}
using namespace IO;
const int maxn=1e6+10;
const int inf=2147483647;
struct sa{
int dis;
int pos;
};
bool operator <(const sa &a,const sa &b) { return a.dis>b.dis; }
priority_queue<sa>q;
struct Edge
{
int to, w, next;
}edge[maxn];
int head[maxn];
int cnt;
void add_edge(int u, int v, int w)
{
edge[cnt].to = v;
edge[cnt].w = w;
edge[cnt].next = head[u];
head[u] = cnt++;
}
int dis[maxn];
bool vis[maxn];
int n,m,s,u,v,w;
void dijkstra(int s){
memset(vis,0,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
dis[s]=0;
q.push( (sa) {0,s});
while(!q.empty())
{
sa ns=q.top();
q.pop();
int x=ns.pos;
if(vis[x]) continue;
vis[x]=1;
for(int i=head[x]; i!=-1 ; i=edge[i].next)
{
if(dis[edge[i].to]>dis[x]+edge[i].w)
{
dis[edge[i].to]=dis[x]+edge[i].w;
q.push( (sa) {dis[edge[i].to],edge[i].to});
}
}
}
}
int main()
{
memset(head,-1,sizeof(head));
cin>>n>>m>>s;
//n=read();m=read();s=read();
for(int i=1; i<=m; i++){
cin>>u>>v>>w;
//u=read();v=read();w=read();
add_edge(u,v,w);
}
dijkstra(s);
for(int i=1;i<=n;i++) {write(dis[i]);pc(' ');}
return 0;
}
菜鸡把一些点说一下。
给数组赋inf,直接 m e m s e t memset memset 0x3f就可以了,不用0x3f3f3f3f。
因为0x3f 转换成十进制为63,每个字节都用ASCII码为63的字符去填充,转换成为二进制就是00111111,占一个字节,int型4个字节就是 00111111001111110011111100111111,约等于无穷大。
#include
using namespace std;
namespace IO{//快读快写,自认为好用。。。
char ibuf[1<<21],*ip=ibuf,*ip_=ibuf;
char obuf[1<<21],*op=obuf,*op_=obuf+(1<<21);
inline char gc(){
if(ip!=ip_)return *ip++;
ip=ibuf;ip_=ip+fread(ibuf,1,1<<21,stdin);
return ip==ip_?EOF:*ip++;
}
inline void pc(char c){
if(op==op_)fwrite(obuf,1,1<<21,stdout),op=obuf;
*op++=c;
}
inline int read(){
register int x=0,ch=gc(),w=1;
for(;ch<'0'||ch>'9';ch=gc())if(ch=='-')w=-1;
for(;ch>='0'&&ch<='9';ch=gc())x=x*10+ch-48;
return w*x;
}
template<class I>
inline void write(I x){
if(x<0)pc('-'),x=-x;
if(x>9)write(x/10);pc(x%10+'0');
}
class flusher_{
public:
~flusher_(){if(op!=obuf)fwrite(obuf,1,op-obuf,stdout);}
}IO_flusher;
}
using namespace IO;
const int maxn=1e6+10;
const int inf=2147483647;//定义最大值,一般为0x3f3f3f3f。
struct sa{
int dis;//权值
int pos;//点(上一个的终点,下一个的起点)
};
bool operator <(const sa &a,const sa &b) { return a.dis>b.dis; }
//重载运算符"<"。后面如果按从小到大排,就写">",这个和实际符号相反。
priority_queue<sa>q;
struct Edge
{
int to, w, next;
}edge[maxn];
//to为终边,w为权值,next表示与这个边起点相同的上一条边的编号
int head[maxn];//head[i]数组,表示以 i 为起点的最后一条边的编号
int cnt;
void add_edge(int u, int v, int w)
{
edge[cnt].to = v;
edge[cnt].w = w;
edge[cnt].next = head[u];
head[u] = cnt++;
}
int dis[maxn];
bool vis[maxn];
int n,m,s,u,v,w;
void dijkstra(int s){
memset(vis,0,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
dis[s]=0;//起点处为0(起点->起点)
q.push( (sa) {0,s});//起点入队
while(!q.empty())
{
sa ns=q.top();
q.pop();
int x=ns.pos;
if(vis[x]) continue;//每个点只访问一次
vis[x]=1;
for(int i=head[x]; i!=-1 ; i=edge[i].next)//遍历以x为起点的所有边
{
if(dis[edge[i].to]>dis[x]+edge[i].w)
{
dis[edge[i].to]=dis[x]+edge[i].w;//更新
q.push( (sa) {dis[edge[i].to],edge[i].to});
//将新的{起点->这个点的目前最短距离,终边(即下一次的起点)}放进队列
}
}
}
}
int main()
{
memset(head,-1,sizeof(head));//全部赋值-1
cin>>n>>m>>s;
//n=read();m=read();s=read();
for(int i=1; i<=m; i++){
cin>>u>>v>>w;
//u=read();v=read();w=read();
add_edge(u,v,w);//有时候会有双向边,要注意。
}
dijkstra(s);
for(int i=1;i<=n;i++) {write(dis[i]);pc(' ');}
return 0;
}
这个题明显复杂的多。
先跑一遍Dijkstra(最短路),然后再去记录单源最短路上经过的边,把路过的边分别去掉,分别跑一边单源最短路取最大值就好啦!
具体操作看代码。
#include
using namespace std;
namespace IO{
char ibuf[1<<21],*ip=ibuf,*ip_=ibuf;
char obuf[1<<21],*op=obuf,*op_=obuf+(1<<21);
inline char gc(){
if(ip!=ip_)return *ip++;
ip=ibuf;ip_=ip+fread(ibuf,1,1<<21,stdin);
return ip==ip_?EOF:*ip++;
}
inline void pc(char c){
if(op==op_)fwrite(obuf,1,1<<21,stdout),op=obuf;
*op++=c;
}
inline int read(){
register int x=0,ch=gc(),w=1;
for(;ch<'0'||ch>'9';ch=gc())if(ch=='-')w=-1;
for(;ch>='0'&&ch<='9';ch=gc())x=x*10+ch-48;
return w*x;
}
template<class I>
inline void write(I x){
if(x<0)pc('-'),x=-x;
if(x>9)write(x/10);pc(x%10+'0');
}
class flusher_{
public:
~flusher_(){if(op!=obuf)fwrite(obuf,1,op-obuf,stdout);}
}IO_flusher;
}
using namespace IO;
const int maxn=1e6+10;
const int minn=1e3+10;
const int inf=2147483647;
struct sa{
int dis;
int pos;
};
bool operator <(const sa &a,const sa &b) { return a.dis>b.dis; }
priority_queue<sa>q;
struct Edge
{
int to, w, next;
}edge[maxn];
int head[maxn];
int cnt;
void add_edge(int u, int v, int w)
{
edge[cnt].to = v;
edge[cnt].w = w;
edge[cnt].next = head[u];
head[u] = cnt++;
}
int dis[maxn];
bool vis[maxn];
int n,m,s,u,v,w;
int cou[maxn],flag[minn][minn];
int f,ans;
void dijkstra(){
s=1;
memset(vis,0,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
dis[s]=0;
q.push( (sa) {0,s});
while(!q.empty())
{
sa ns=q.top();
q.pop();
int x=ns.pos;
if(vis[x]) continue;
vis[x]=1;
for(int i=head[x]; i!=-1 ; i=edge[i].next)
{
if((!flag[x][edge[i].to])&&dis[edge[i].to]>dis[x]+edge[i].w)
{//多了的这个条件,就是相当于删一条最短路的边。
if(!f) cou[edge[i].to]=x;//用链表存最短路的点,最后肯定是con[n]=?,然后下面有个循环从n遍历,就知道每条边的起点与终点了。
dis[edge[i].to]=dis[x]+edge[i].w;
q.push( (sa) {dis[edge[i].to],edge[i].to});
}
}
}
}
int main()
{
memset(head,-1,sizeof(head));
//cin>>n>>m;
n=read();m=read();
for(int i=1; i<=m; i++){
//cin>>u>>v>>w;
u=read();v=read();w=read();
add_edge(u,v,w);
add_edge(v,u,w);//存双向边
}
dijkstra();
f=1;//一开始f=0,就是为了储存最短路,现在储存完了,就让f等于1。
for(int i=n;i!=1;i=cou[i]){
flag[cou[i]][i]=1;
flag[i][cou[i]]=1;//flag二维数组,一维是起点,一维是终点。就是为了记录这条边不走。
dijkstra();
flag[cou[i]][i]=0;//再复原
flag[i][cou[i]]=0;
ans=max(ans,dis[n]);//取最大值
}
//cout<
write(ans);pc('\n');
return 0;
-
典型的一类问题:从多到一的最短路变式的路径反转操作——反向建边
什么意思呢?
首先这是有向图,邮递员从一对多跑过去,还要多对一跑回来。一对多直接最短路跑一遍就行了,但多对一怎么办?
我们假设一条最短路径是这样的(s为起点,t为终点) s − > a − > b − > t s->a->b->t s−>a−>b−>t
也就是这么三条边 s − > a a − > b b − > t s->a \\ a->b\\ b->t s−>aa−>bb−>t
那么将 s − > t s->t s−>t的最短路反过来 s < − a a < − b b < − t s<-a\\a<-b\\b<-t s<−aa<−bb<−t也是 t − > s t->s t−>s的最短路。
也就是说多对一的最短路 ≡ \equiv ≡反向建图一对多的最短路
上代码!
#include
using namespace std;
namespace IO{
char ibuf[1<<21],*ip=ibuf,*ip_=ibuf;
char obuf[1<<21],*op=obuf,*op_=obuf+(1<<21);
inline char gc(){
if(ip!=ip_)return *ip++;
ip=ibuf;ip_=ip+fread(ibuf,1,1<<21,stdin);
return ip==ip_?EOF:*ip++;
}
inline void pc(char c){
if(op==op_)fwrite(obuf,1,1<<21,stdout),op=obuf;
*op++=c;
}
inline int read(){
register int x=0,ch=gc(),w=1;
for(;ch<'0'||ch>'9';ch=gc())if(ch=='-')w=-1;
for(;ch>='0'&&ch<='9';ch=gc())x=x*10+ch-48;
return w*x;
}
template<class I>
inline void write(I x){
if(x<0)pc('-'),x=-x;
if(x>9)write(x/10);pc(x%10+'0');
}
class flusher_{
public:
~flusher_(){if(op!=obuf)fwrite(obuf,1,op-obuf,stdout);}
}IO_flusher;
}
using namespace IO;
const int maxn=1e6+10;
const int inf=2147483647;
struct sa{
int dis;
int pos;
};
bool operator <(const sa &a,const sa &b) { return a.dis>b.dis; }
priority_queue<sa>q;
struct Edge
{
int to, w, next;
}edge[maxn];
int head[maxn];
int cnt;
void add_edge(int u, int v, int w)
{
edge[cnt].to = v;
edge[cnt].w = w;
edge[cnt].next = head[u];
head[u] = cnt++;
}
int dis[maxn];
bool vis[maxn];
int n,m,s,u,v,w;
void dijkstra(int s){
memset(vis,0,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
dis[s]=0;
q.push( (sa) {0,s});
while(!q.empty())
{
sa ns=q.top();
q.pop();
int x=ns.pos;
if(vis[x]) continue;
vis[x]=1;
for(int i=head[x]; i!=-1 ; i=edge[i].next)
{
if(dis[edge[i].to]>dis[x]+edge[i].w)
{
dis[edge[i].to]=dis[x]+edge[i].w;
q.push( (sa) {dis[edge[i].to],edge[i].to});
}
}
}
}
int main()
{
memset(head,-1,sizeof(head));
cin>>n>>m;
//n=read();m=read();s=read();
for(int i=1; i<=m; i++){
cin>>u>>v>>w;
//u=read();v=read();w=read();
add_edge(u,v,w);
add_edge(v+n,u+n,w);
}
long long ans=0;
dijkstra(1);
for(int i=1;i<=n;i++)
ans+=dis[i];
dijkstra(1+n);
for(int i=1+n;i<=n<<1;i++)
ans+=dis[i];
cout<<ans<<endl;
return 0;
}
与第一个车站建立一条边权为0的边,对于它所相连的其他车站,建立边权为1的边。跑一遍即可。
#include
using namespace std;
namespace IO{
char ibuf[1<<21],*ip=ibuf,*ip_=ibuf;
char obuf[1<<21],*op=obuf,*op_=obuf+(1<<21);
inline char gc(){
if(ip!=ip_)return *ip++;
ip=ibuf;ip_=ip+fread(ibuf,1,1<<21,stdin);
return ip==ip_?EOF:*ip++;
}
inline void pc(char c){
if(op==op_)fwrite(obuf,1,1<<21,stdout),op=obuf;
*op++=c;
}
inline int read(){
register int x=0,ch=gc(),w=1;
for(;ch<'0'||ch>'9';ch=gc())if(ch=='-')w=-1;
for(;ch>='0'&&ch<='9';ch=gc())x=x*10+ch-48;
return w*x;
}
template<class I>
inline void write(I x){
if(x<0)pc('-'),x=-x;
if(x>9)write(x/10);pc(x%10+'0');
}
class flusher_{
public:
~flusher_(){if(op!=obuf)fwrite(obuf,1,op-obuf,stdout);}
}IO_flusher;
}
using namespace IO;
const int maxn=1e6+10;
const int inf=0x3f3f3f3f;
struct sa{
int dis;
int pos;
};
bool operator <(const sa &a,const sa &b) { return a.dis>b.dis; }
priority_queue<sa>q;
struct Edge
{
int to,w,next;
}edge[maxn];
int head[maxn];
int cnt;
void add_edge(int u, int v,int w)
{
edge[cnt].to = v;
edge[cnt].w= w;
edge[cnt].next = head[u];
head[u] = cnt++;
}
int dis[maxn];
bool vis[maxn];
int n,m,s,u,v,w,t;
void dijkstra(int s){
memset(vis,0,sizeof(vis));
memset(dis,0x3f,sizeof(dis));
dis[s]=0;
q.push( (sa) {0,s});
while(!q.empty())
{
sa ns=q.top();
q.pop();
int x=ns.pos;
if(vis[x]) continue;
vis[x]=1;
for(int i=head[x]; i!=-1 ; i=edge[i].next)
{
if(dis[edge[i].to]>dis[x]+edge[i].w)
{
dis[edge[i].to]=dis[x]+edge[i].w;
q.push( (sa) {dis[edge[i].to],edge[i].to});
}
}
}
}
int main()
{
memset(head,-1,sizeof(head));
cin>>n>>s>>t;
//n=read();m=read();s=read();
for(int i=1;i<=n;i++){
cin>>m;
//u=read();v=read();w=read();
for(int j=1;j<=m;j++)
{
cin>>v;
if (j==1) add_edge(i,v,0);
else add_edge(i,v,1);
}
}
dijkstra(s);
if(dis[t]!=inf) cout<<dis[t]<<endl;
else cout<<"-1"<<endl;
return 0;
}
无向图。
#include
using namespace std;
namespace IO{
char ibuf[1<<21],*ip=ibuf,*ip_=ibuf;
char obuf[1<<21],*op=obuf,*op_=obuf+(1<<21);
inline char gc(){
if(ip!=ip_)return *ip++;
ip=ibuf;ip_=ip+fread(ibuf,1,1<<21,stdin);
return ip==ip_?EOF:*ip++;
}
inline void pc(char c){
if(op==op_)fwrite(obuf,1,1<<21,stdout),op=obuf;
*op++=c;
}
inline int read(){
register int x=0,ch=gc(),w=1;
for(;ch<'0'||ch>'9';ch=gc())if(ch=='-')w=-1;
for(;ch>='0'&&ch<='9';ch=gc())x=x*10+ch-48;
return w*x;
}
template<class I>
inline void write(I x){
if(x<0)pc('-'),x=-x;
if(x>9)write(x/10);pc(x%10+'0');
}
class flusher_{
public:
~flusher_(){if(op!=obuf)fwrite(obuf,1,op-obuf,stdout);}
}IO_flusher;
}
using namespace IO;
const int maxn=1e6+10;
const int inf=2147483647;
struct sa{
int dis;
int pos;
};
bool operator <(const sa &a,const sa &b) { return a.dis>b.dis; }
priority_queue<sa>q;
struct Edge
{
int to, w, next;
}edge[maxn];
int head[maxn];
int cnt;
void add_edge(int u, int v, int w)
{
edge[cnt].to = v;
edge[cnt].w = w;
edge[cnt].next = head[u];
head[u] = cnt++;
}
int dis[maxn];
bool vis[maxn];
int n,m,s,u,v,w;
int main()
{
while(cin>>n>>m){
//n=read();m=read();
s=1;
memset(head,-1,sizeof(head));
memset(dis,-1,sizeof(dis));
memset(vis,0,sizeof(vis));
for(int i=1; i<=m; i++){
//u=read();v=read();w=read();
cin>>u>>v>>w;
add_edge(u,v,w);
add_edge(v,u,w);
}
for(int i=1; i<=n; i++)
dis[i]=inf;
dis[s]=0;
q.push( (sa) {0,s});
while(!q.empty())
{
sa ns=q.top();
q.pop();
int x=ns.pos;
if(vis[x]) continue;
vis[x]=1;
for(int i=head[x]; i!=-1 ; i=edge[i].next)
{
if(dis[edge[i].to]>dis[x]+edge[i].w)
{
dis[edge[i].to]=dis[x]+edge[i].w;
q.push( (sa) {dis[edge[i].to],edge[i].to});
}
}
}
cout<<dis[n]<<endl;
}
return 0;
}
#include
using namespace std;
namespace IO{
char ibuf[1<<21],*ip=ibuf,*ip_=ibuf;
char obuf[1<<21],*op=obuf,*op_=obuf+(1<<21);
inline char gc(){
if(ip!=ip_)return *ip++;
ip=ibuf;ip_=ip+fread(ibuf,1,1<<21,stdin);
return ip==ip_?EOF:*ip++;
}
inline void pc(char c){
if(op==op_)fwrite(obuf,1,1<<21,stdout),op=obuf;
*op++=c;
}
inline int read(){
register int x=0,ch=gc(),w=1;
for(;ch<'0'||ch>'9';ch=gc())if(ch=='-')w=-1;
for(;ch>='0'&&ch<='9';ch=gc())x=x*10+ch-48;
return w*x;
}
template<class I>
inline void write(I x){
if(x<0)pc('-'),x=-x;
if(x>9)write(x/10);pc(x%10+'0');
}
class flusher_{
public:
~flusher_(){if(op!=obuf)fwrite(obuf,1,op-obuf,stdout);}
}IO_flusher;
}
using namespace IO;
const int maxn=1e6+10;
const int inf=2147483647;
struct sa{
int dis;
int pos;
};
bool operator <(const sa &a,const sa &b) { return a.dis>b.dis; }
priority_queue<sa>q;
struct Edge
{
int to, w, next;
}edge[maxn];
int head[maxn];
int cnt;
void add_edge(int u, int v, int w)
{
edge[cnt].to = v;
edge[cnt].w = w;
edge[cnt].next = head[u];
head[u] = cnt++;
}
int dis[maxn];
bool vis[maxn];
int n,m,s,u,v,w,t;
int main()
{
while(cin>>n>>m){
//n=read();m=read();
memset(head,-1,sizeof(head));
memset(dis,-1,sizeof(dis));
memset(vis,0,sizeof(vis));
for(int i=1; i<=m; i++){
//u=read();v=read();w=read();
cin>>u>>v>>w;
add_edge(u,v,w);
}
cin>>s>>t;
for(int i=1; i<=n; i++)
dis[i]=inf;
dis[s]=0;
q.push( (sa) {0,s});
while(!q.empty())
{
sa ns=q.top();
q.pop();
int x=ns.pos;
if(vis[x]) continue;
vis[x]=1;
for(int i=head[x]; i!=-1 ; i=edge[i].next)
{
if(dis[edge[i].to]>dis[x]+edge[i].w)
{
dis[edge[i].to]=dis[x]+edge[i].w;
q.push( (sa) {dis[edge[i].to],edge[i].to});
}
}
}
if(dis[t]!=2147483647) cout<<dis[t]<<endl;
else cout<<"-1"<<endl;
}
return 0;
}
完结。