1.条件类型最短路

https://ac.nowcoder.com/acm/contest/370/B

题意: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);
    }
}

未完待续