题意:

有N个结点,由M条双向边连接,每条边有权值。可以把最多k条边的权值改为0。问从1到N的最短路为多少。其中

思路:

法一:拆点。

把图分为k层,层与层之间的路权值为0,每次走上一条权值为0的边相当于在层之间走。

注意数组开的大小。

如图:

法二:DP思想。

:到第i个结点把j条边权值改为0的最短路。

根据松弛有,还有一种转移是层与层之间,即权值为0的情况,

复杂度为

代码:

法一:

typedef long long ll;
#define INF 0x3f3f3f3f3f3f3f3f
int top;
int head[500010];
struct edge
{
    int to;
    ll cost;
    int next;
}eg[5000010];
void add(int a,int b,ll c)
{
    eg[top].cost=c;
    eg[top].to=b;
    eg[top].next=head[a];
    head[a]=top++;
}
typedef pair<ll,int>p;
ll dis[500010];
int n;
void dijkstra()
{
    fill(dis+1,dis+n+1,INF);
    dis[1]=0;
    priority_queue<p,vector<p>,greater<p> >q;
    q.push(p(0,1));
    while(!q.empty())
    {
        p temp=q.top();
        q.pop();
        ll w=temp.first;
        int id=temp.second;
        if(w>dis[id])continue;
        for(int i=head[id];i!=-1;i=eg[i].next)
        {
            edge &e=eg[i];
            if(w+e.cost<dis[e.to])
            {
                dis[e.to]=w+e.cost;
                q.push(p(dis[e.to],e.to));
            }
        }
    }
    /*for(int i=1;i<=n;i++)
        printf("%lld ",dis[i]);
    printf("\n");*/
}
int main()
{
    int m,k,x,y;
    ll w;
    scanf("%d%d%d",&n,&m,&k);
    top=0;
    memset(head,-1,sizeof(head));
    while(m--)
    {
        scanf("%d%d%lld",&x,&y,&w);
        for(int i=0;i<=k;i++)
        {
            add(x+i*n,y+i*n,w);
            add(y+i*n,x+i*n,w);
            if(i!=k)
            {
                add(x+i*n,y+(i+1)*n,0);
                add(y+i*n,x+(i+1)*n,0);
            }
        }
    }
    n=(k+1)*n;
    /*for(int i=1;i<=n;i++)
    {
        for(int j=head[i];j!=-1;j=eg[j].next)
            printf("%d ",eg[j].to);
        printf("\n");
    }*/
    dijkstra();
    printf("%lld\n",dis[n]);
    return 0;
}

法二:

typedef long long ll;
#define INF 0x3f3f3f3f3f3f3f3f
int top;
int head[10010];
struct edge
{
    int to;
    ll cost;
    int next;
}eg[100010];
void add(int a,int b,ll c)
{
    eg[top].cost=c;
    eg[top].to=b;
    eg[top].next=head[a];
    head[a]=top++;
}
typedef pair<int,int> pp;
typedef pair<ll,pp>p;
ll dis[10010][25];
bool vis[10010][25];
int n;
int k;
void dijkstra()
{
    memset(dis,0x3f,sizeof(dis));
    memset(vis,0,sizeof(vis));
    dis[1][0]=0;
    priority_queue<p,vector<p>,greater<p> >q;
    q.push(p(0,pp(1,0)));
    while(!q.empty())
    {
        p temp=q.top();
        q.pop();
        ll w=temp.first;
        int id=temp.second.first;
        int cur=temp.second.second;
        if(vis[id][cur])continue;
        vis[id][cur]=true;
        for(int i=head[id];i!=-1;i=eg[i].next)
        {
            edge &e=eg[i];
            if(w+e.cost<dis[e.to][cur])
            {
                dis[e.to][cur]=w+e.cost;
                q.push(p(dis[e.to][cur],pp(e.to,cur)));
            }
            if(cur<k&&w<dis[e.to][cur+1])
            {
                dis[e.to][cur+1]=w;
                q.push(p(dis[e.to][cur+1],pp(e.to,cur+1)));
            }
        }
    }
}
int main()
{
    int m,x,y;
    ll w;
    scanf("%d%d%d",&n,&m,&k);
    top=0;
    memset(head,-1,sizeof(head));
    while(m--)
    {
        scanf("%d%d%lld",&x,&y,&w);
        add(x,y,w);
        add(y,x,w);
    }
    dijkstra();
    printf("%lld\n",dis[n][k]);
    return 0;
}

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!

矩阵计数问题 容斥/dp Previous
南京网络赛E 状压dp(反省...) Next