1.条件类型最短路
题意:n个点,m无向边,n个点有一部分是特殊的点,求从1走到n最短路是多少。并且该最短路满足走过的特殊点不超过K.
分析: 将所有点的状态分离成K个点(K分层图),表示到当前该点的走过的特殊点有 个。然后跑一遍dij即可。(dis多建一维条件跑dij也可以)
#include<bits/stdc++.h>
#define ll long long
#define inf 0x7f7f7f7f
#define pr pair<ll,ll>
using namespace std;
const int N=4e6+10;
struct node{
int v,len,next;
}a[N*2];
int pre[N],cnt=0;
ll dis[N],vis[N];
void add( int u,int v,int len )
{
// a[cnt].v=v , a[cnt].len=len , a[cnt].next=pre[u];
a[cnt]={ v,len,pre[u] };
pre[u]=cnt++;
}
void init()
{
memset(pre,-1,sizeof(pre)),cnt=0;
}
void dijstra( int s ) // 起点
{
memset( dis,inf,sizeof(dis) );
memset( vis,0,sizeof(vis) );
priority_queue<pr,vector<pr>,greater<pr> > q;
q.push( make_pair(0,s) );
dis[s]=0;
while( q.size() )
{
int u=q.top().second;
q.pop();
vis[u]=1;
for( int i=pre[u];~i;i=a[i].next )
{
int v=a[i].v,len=a[i].len;
if( !vis[v] && dis[v]>dis[u]+len )
{
dis[v]=dis[u]+len;
q.push( make_pair(dis[v],v) );
}
}
}
}
int tag[N];
int main()
{
init();
int n,m,k;
scanf("%d%d%d",&n,&m,&k);
for( int i=1;i<=n;i++ ) scanf("%d",&tag[i]);
if( tag[1] ) k--;
if( tag[n] ) k++;
for( int i=1;i<=m;i++ )
{
int a,b,c;scanf("%d%d%d",&a,&b,&c);
for( int j=0;j<=k;j++ )
{
if( !tag[b] ) add(a+n*j,b+n*j,c);
if( !tag[a] ) add(b+n*j,a+n*j,c);
}
for( int j=0;j<k;j++ )
{
if( tag[b] ) add(a+n*j,b+n*j+n,c);
if( tag[a] ) add(b+n*j,a+n*j+n,c);
}
}
ll ans=inf;
dijstra(1);
for( int i=1;i<=k+1;i++ ) ans=min(ans,dis[i*n]);
if( ans!=inf ) printf("%lld\n",ans);
else puts("-1");
}2.最短路K次免费(半价都一样)
#include<bits/stdc++.h>
#include<queue>
#define int long long
#define INF 1e18
using namespace std;
inline int read()
{
int f=1,w=0;char s=getchar();
for( ;!isdigit(s);s=='-' && (f=-1),s=getchar());
for( ;isdigit(s);w=w*10+s-48,s=getchar());
return w*f;
}
int dis[200010][60],n,m,p,head[200010],cnt;
// head[i] 路线起始位置索引到 可能到的位置 结合 edge[i]索引
// dis[i][j] i表示到位置i j表示打折次数 dis[i][j]表示最小花费
struct Edge{
int from,to,next,dis;
}edge[1000010];
inline void addedge( int u,int v,int w ) // 存有向网
{
cnt++;
edge[cnt].from=u;
edge[cnt].to=v;
edge[cnt].dis=w;
edge[cnt].next=head[u];
head[u]=cnt;
}
struct node{
int num,dis,tim;
friend bool operator < (node a,node b) //优先级
{
return a.dis>b.dis;
}
};
priority_queue<node> q; // 优先队列
inline void dij(int s)
{
int u,v,w,i,j,k,tim;
dis[s][0]=0;
q.push( (node){s,0,0} );
while( !q.empty() )
{
node front=q.top();
q.pop();
u=front.num; // u表示到位置
tim=front.tim; // tim 表示打折次数
if(tim>p) continue;
if( front.dis>dis[u][tim] ) continue;
for(i=head[u];i;i=edge[i].next ) // 有点bfs的意思
{
v=edge[i].to;
w=edge[i].dis;
if( dis[v][tim]>dis[u][tim]+w )
{
dis[v][tim]=dis[u][tim]+w;
q.push( (node) {v,dis[v][tim],tim} );
}
if( dis[v][tim+1]>dis[u][tim]+edge[i].dis/2 )
{
dis[v][tim+1]=dis[u][tim]+edge[i].dis/2;
q.push( (node) {v,dis[v][tim+1],tim+1} );
}
}
}
return;
}
signed main(){
n=read();m=read();p=read();
int i,j,k,st,ed;st=1;ed=n;
for( i=1;i<=m;i++ )
{
int x,y,z;
x=read();y=read();z=read();
addedge(x,y,z);
}
//// 调试
// cout<<endl;
// for( int i=1;i<=n;i++ )
// {
// // printf("%d ",head[i]);
// for(j=head[i];j;j=edge[j].next )
// {
// printf("%d ",j);
// }cout<<endl;
// }cout<<endl;
//
for( int i=0;i<=200000;i++ ) // 初始化操作
{
for( int j=0;j<=10;j++ )
{
dis[i][j]=INF;
}
}
dij(st);
int ans=INF;
for( int i=0;i<=p;i++ )
{
ans=min( ans,dis[n][i] );
}
if( ans==INF ) cout<<-1<<endl;
else cout<<ans<<endl;
return 0;
}HDU6797
3.n阶完全图,每条边都有一个边权,你可以去掉k条边,使得最短路的长度尽量长。求最短路最长是多少。
暴力修改最短路上的边,然后跑最短路,迭代k次。答案去最大。
#include<bits/stdc++.h>
#define pr pair<int,int>
typedef long long ll;
using namespace std;
const int inf=0x3f3f3f3f;
const int maxn=55;
const int maxm=300;
bool vis[maxn];
int d[maxn],g[maxn][maxn];
int n,m,s,e,path[maxn];
int ans;
void dijkstra()
{
priority_queue<pr> q;
for( int i=1;i<=n;i++ ) d[i]=inf,vis[i]=false;
d[s]=0;
q.push( make_pair(0,s) );
while( !q.empty() )
{
int x=q.top().second;
q.pop();
if( vis[x] ) continue;
vis[x]=true;
for( int v=1;v<=n;v++ )
{
if( !g[x][v] ) continue;
int w=g[x][v];
if( d[v]>d[x]+w )
{
d[v]=d[x]+w;
path[v]=x;
q.push( make_pair(-d[v],v) );
}
}
}
}
void dfs( int x )
{
dijkstra();
if( x==0 )
{
ans=max(ans,d[n]);
return;
}
int j=n,p[55],num=0;
p[++num]=n;
while( path[j] ) // 搜索路径
{
p[++num]=path[j];
j=path[j];
}
for( int i=1;i<num;i++ )
{
int ww=g[p[i]][p[i+1]];
g[p[i]][p[i+1]]=g[p[i+1]][p[i]]=0;
dfs(x-1);
g[p[i]][p[i+1]]=g[p[i+1]][p[i]]=ww;
}
}
int main()
{
int T;
scanf("%d",&T);
while( T-- )
{
ans=0;
int k;
scanf("%d%d",&n,&k);
for( int i=1;i<=n*(n-1)/2;i++ )
{
int u,v,w;scanf("%d%d%d",&u,&v,&w);
g[u][v]=g[v][u]=w;
}
s=1;
dfs(k);
printf("%d\n",ans);
}
}
未完待续

京公网安备 11010502036488号