【CF 507E】Breaking Good

【CF 507E】Breaking Good

双条件最短路

每个路有已搭建和未搭建两种状态 需要把经过的路都建起 为经过的路都拆掉

优先经过最少条路 同样少的路走改动(搭建+拆掉)最小的

最短路跑完后把最短的路上的路径标记一下

bfs输出拆除和搭建 在最短路径上的路 未建的搭建 不在的建好的拆掉

通过此题试了一下spfa的一个小优化还有dijkstra的优先队列优化

不过别看spfa加优化快了点 前两天做了个专门卡这个优化的题……想方设法让他多跑就是。。HDOJ 4889 有兴趣的可以去瞅瞅

此题代码如下:

//spfa 109ms
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define sz 100000
#define INF 0x3f3f3f3f

using namespace std;

typedef struct Edge//邻接表建图
{
    int v,next,hs;
    int in;
}Edge;

bool vis[sz+1];
Edge eg[2*sz+2];
int head[sz+1];
int rep[sz+1],dis[sz+1],site[sz+1],pre[sz+1];//rep重建路数 dis经过路数 site当前点与前驱点间路下标 用以标记 pre前驱
int alb,n,m,tp;

void Add(int u,int v,int w)
{
    eg[tp].v = v;
    eg[tp].hs = w;
    eg[tp].next = head[u];
    eg[tp].in = 0;
    head[u] = tp++;
}

void spfa()
{
    queue <int> q;
    memset(vis,0,sizeof(vis));
    memset(dis,INF,sizeof(dis));
    memset(rep,INF,sizeof(rep));
    int i,u,v,p,ned;

    q.push(1);
    dis[1]  = rep[1] = 0;
    pre[1] = vis[1] = 1;

    while(!q.empty())
    {
        u = q.front();
        q.pop();
        if(u == n) return;
        for(i = head[u]; i != -1; i = eg[i].next)
        {
            ned = eg[i].hs^1;
            v = eg[i].v;
            if(dis[u]+1 < dis[v] || (dis[u]+1 == dis[v] && rep[u] + ned < rep[v]))
            {
                site[v] = i;
                pre[v] = u;
                dis[v] = dis[u]+1;
                rep[v] = rep[u] + ned;
                if(!vis[v])
                {
                    q.push(v);
                    vis[v] = 1;
                }
            }
        }
    }

}

void Bfs()
{
    memset(vis,0,sizeof(vis));
    queue <int> q;
    q.push(1);
    int i,u,v;
    vis[1] = 1;

    while(!q.empty())
    {
        u = q.front();
        q.pop();
        for(i = head[u]; i != -1; i = eg[i].next)
        {
            if(eg[i].in == -1) continue;
            v = eg[i].v;
            if(!eg[i].hs && eg[i].in)//路未建且在路径中
            {
                printf("%d %d 1\n",u,v);
            }
            else if(eg[i].hs && !eg[i].in)//路已建但不在路径中
            {
                printf("%d %d 0\n",u,v);
            }
            eg[i].in = eg[i^1].in = -1;
            if(!vis[v])
            {
                q.push(v);
                vis[v] = 1;
            }
        }
    }
    puts("");
}

int main()
{
    int u,v,w;
    scanf("%d %d",&n,&m);
    memset(head,-1,sizeof(head));
    tp = alb = 0;

    while(m--)
    {
        scanf("%d %d %d",&u,&v,&w);
        Add(u,v,w);
        Add(v,u,w);
        if(w) alb++;//累加已建路数
    }

    spfa();

    for(u = n; u != pre[u]; u = pre[u]) eg[site[u]].in = eg[site[u]^1].in = 1;//标记最短路径上的路
    printf("%d\n",rep[n]*2 + alb - dis[n]);//rep+(alb-(dis-rep))
    Bfs();

    return 0;
}
//spfa+优化93ms
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#define sz 100000
#define INF 0x3f3f3f3f

using namespace std;

typedef struct Edge
{
    int v,next,hs;
    int in;
}Edge;

bool vis[sz+1];
Edge eg[2*sz+2];
int head[sz+1];
int rep[sz+1],dis[sz+1],site[sz+1],pre[sz+1];
int alb,n,m,tp;

void Add(int u,int v,int w)
{
    eg[tp].v = v;
    eg[tp].hs = w;
    eg[tp].next = head[u];
    eg[tp].in = 0;
    head[u] = tp++;
}

void spfa()
{
    deque <int> q;
    memset(vis,0,sizeof(vis));
    memset(dis,INF,sizeof(dis));
    memset(rep,INF,sizeof(rep));
    int i,u,v,p,ned;

    q.push_front(1);
    dis[1]  = rep[1] = 0;
    pre[1] = vis[1] = 1;

    while(!q.empty())
    {
        u = q.front();
        q.pop_front();
        if(u == n) return;
        for(i = head[u]; i != -1; i = eg[i].next)
        {
            ned = eg[i].hs^1;
            v = eg[i].v;
            if(dis[u]+1 < dis[v] || (dis[u]+1 == dis[v] && rep[u] + ned < rep[v]))
            {
                site[v] = i;
                pre[v] = u;
                dis[v] = dis[u]+1;
                rep[v] = rep[u] + ned;
                if(!vis[v])
                {
                    if(!q.empty()) p = q.front();
                    if(!q.empty() && (dis[v] < dis[p] || (dis[v] == dis[p] && rep[v] < rep[p])) )q.push_front(v);
                    else q.push_back(v);
                    vis[v] = 1;
                }
            }
        }
    }

}

void Bfs()
{
    memset(vis,0,sizeof(vis));
    queue <int> q;
    q.push(1);
    int i,u,v;
    vis[1] = 1;

    while(!q.empty())
    {
        u = q.front();
        q.pop();
        for(i = head[u]; i != -1; i = eg[i].next)
        {
            if(eg[i].in == -1) continue;
            v = eg[i].v;
            if(!eg[i].hs && eg[i].in)
            {
                printf("%d %d 1\n",u,v);
            }
            else if(eg[i].hs && !eg[i].in)
            {
                printf("%d %d 0\n",u,v);
            }
            eg[i].in = eg[i^1].in = -1;
            if(!vis[v])
            {
                q.push(v);
                vis[v] = 1;
            }
        }
    }
    puts("");
}

int main()
{
    int u,v,w;
    scanf("%d %d",&n,&m);
    memset(head,-1,sizeof(head));
    tp = alb = 0;

    while(m--)
    {
        scanf("%d %d %d",&u,&v,&w);
        Add(u,v,w);
        Add(v,u,w);
        if(w) alb++;
    }

    spfa();

    for(u = n; u != pre[u]; u = pre[u]) eg[site[u]].in = eg[site[u]^1].in = 1;
    printf("%d\n",rep[n]*2 + alb - dis[n]);
    Bfs();

    return 0;
}
//dijkstra+优化108ms
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <vector>
#define sz 100000
#define INF 0x3f3f3f3f

using namespace std;

typedef struct Edge
{
    int v,next,hs;
    int in;
}Edge;

bool vis[sz+1];
Edge eg[2*sz+2];
int head[sz+1];
int rep[sz+1],dis[sz+1],site[sz+1],pre[sz+1];
int alb,n,m,tp;

void Add(int u,int v,int w)
{
    eg[tp].v = v;
    eg[tp].hs = w;
    eg[tp].next = head[u];
    eg[tp].in = 0;
    head[u] = tp++;
}

struct cmp
{
    bool operator() (int a,int b)
    {
        return dis[a] > dis[b] || (dis[a] == dis[b] && rep[a] > rep[b]);
    }
};

void Dijkstra()
{
    priority_queue <int,vector<int>,cmp> q;
    memset(vis,0,sizeof(vis));
    memset(dis,INF,sizeof(dis));
    memset(rep,INF,sizeof(rep));
    dis[1]  = rep[1] = 0;
    pre[1] = 1;
    q.push(1);
    int i,v,p,mm,j,ss,ned;
    while(1)
    {
        p = q.top();
        q.pop();

        if(p == n) return;
        vis[p] = 1;

        for(j = head[p]; j != -1; j = eg[j].next)
        {
            v = eg[j].v;
            ned = eg[j].hs^1;
            if(!vis[v] && (dis[p] + 1 < dis[v] || (dis[p]+1 == dis[v] && rep[p] + ned < rep[v])))
            {
                dis[v] = dis[p] + 1;
                rep[v] = rep[p] +ned;
                site[v] = j;
                pre[v] = p;
                q.push(v);
            }
        }
    }
}

void Bfs()
{
    memset(vis,0,sizeof(vis));
    queue <int> q;
    q.push(1);
    int i,u,v;
    vis[1] = 1;

    while(!q.empty())
    {
        u = q.front();
        q.pop();
        for(i = head[u]; i != -1; i = eg[i].next)
        {
            if(eg[i].in == -1) continue;
            v = eg[i].v;
            if(!eg[i].hs && eg[i].in)
            {
                printf("%d %d 1\n",u,v);
            }
            else if(eg[i].hs && !eg[i].in)
            {
                printf("%d %d 0\n",u,v);
            }
            eg[i].in = eg[i^1].in = -1;
            if(!vis[v])
            {
                q.push(v);
                vis[v] = 1;
            }
        }
    }
    puts("");
}

int main()
{
    int u,v,w;
    scanf("%d %d",&n,&m);
    memset(head,-1,sizeof(head));
    tp = alb = 0;

    while(m--)
    {
        scanf("%d %d %d",&u,&v,&w);
        Add(u,v,w);
        Add(v,u,w);
        if(w) alb++;
    }

    Dijkstra();
    for(u = n; u != pre[u]; u = pre[u]) eg[site[u]].in = eg[site[u]^1].in = 1;
    printf("%d\n",rep[n]*2 + alb - dis[n]);
    Bfs();

    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-07-29 08:59:01

【CF 507E】Breaking Good的相关文章

【CF 520D】Cubes

[CF 520D]Cubes 怎么说呢--英语阅读题+超级大模拟-- 最重要的是知道怎么出来的数据...题意好懂 xy坐标内给出几个单位正方形 以正方形左下点坐标给出 y=0为地面 正方形下面或者左右下方至少存在一个正方形他才能稳定.. 正方形按0~m-1标号 每次只能取出不影响整体结构的正方形 甲乙玩一个游戏 交替取正方形 每取下一个按从左到右的顺序排好 得到一个大数 重点来了! 取出的数是m进制 转换为十进制是最终结果 甲希望结果最大 乙希望结果最小 问结果为多少 甲先取 题意明白了模拟就行

【CF 474E】Pillars

[CF 474E]Pillars 离散化+线段树dp 大半夜写出来了...好长好长好长好长好挫--先把高度排序离散化 我又开了个哈希数组用来查某点对应离散后的点 然后遍历每个点时二分出满足题意的区间(1~h-d)(h+d~max) 然后线段树查两个区间当前最大长度的序列 累计到当前点对应的树内点 同时更新他的父亲点们的最大长度 再把之前最大长度的末尾作为当前点的前驱 如果没有就用当前点自己做前驱 最后输出树根存的节点的前驱们(即为树内最长的序列) 各种节点哈希的有点混乱--代码--看乱了就别看了

【CF 460C】Present

[CF 460C]Present 二分+贪心 二分最矮高度的最大值 每二分一个遍历看是否可达 可达low = mid+1不可达high = mid-1 可达的判断用贪心即可 改点长度不足时 在改点设置浇水点 同是在i+w设置断水 之后每个点都继承前一个点的浇水量 到i+w时减少i处浇的水即可 代码如下: #include <iostream> #include <cstdio> #include <cstring> #define sz 100000 #define l

【CF 459D】 Pashmak and Parmida&#39;s problem

[CF 459D] Pashmak and Parmida's problem 预处理+线段树求逆序对 新学了树状数组 很适合这题 来一发 代码如下: #include <iostream> #include <cstdio> #include <cstdlib> #include <map> #include <cstring> #define ll long long using namespace std; map <int,int&

【CF 515D】 Drazil and Tiles

[CF 515D] Drazil and Tiles 拓扑的思想 如果满足条件 '.'未遍历完之前肯定存在度为1的点(上下左右仅有一个'.') 遍历到一个1度点u时 将与他连的点v用对应括号括起 此时v也已匹配 入度归零 同时将与v相连的其余点入度减1 不断遍历知道遍历完所有'.' 若能遍历完 则满足条件否则无解或多解 (吐槽一下 原本用的纯粹拓扑思路 想想也是绝对要T的..后来改换BFS 代码如下: #include <iostream> #include <cstdio> #i

【CF 566F】 Clique in the Divisibility Graph

[CF 566F] Clique in the Divisibility Graph 最大团模型的dp 数做点 能约分的一对数间有路 问最大团(最大完全子图) 用最长公共子序列做法 dp出最长路 由于一个数约数的约数也是这个数的约数 所以只要能连起来就是个完全子图 代码如下: #include <iostream> #include <cstdlib> #include <cstdio> #include <cstring> #include <alg

【线段树】【树状数组】【CF 121E】幸运数列

1922. [CF 121E]幸运数列 ★★★ 输入文件:cf121e.in 输出文件:cf121e.out 简单对比 时间限制:3 s 内存限制:256 MB [题目描述] 对于欧洲人来说,"幸运数"是指那些十进制只由4或7组成的数.财务员Petya需要维护一个支持如下操作的整数数列: add l r d - 表示将[l, r]区间内的所有数加上一个正整数d(). count l r - 统计[l, r]区间内有多少个"幸运数".() 请你帮助Petya实现它.

【CF Gym100228】Graph of Inversions

Portal --> qwq(貌似是CodeForces Gym 100228 (ECNA2003) - I) Description 对于长度为 \(n\) 的序列 \(A\) ,定义其逆序图 \(G\) 如下:无向图 \(G\)有\(n\) 个节点,编号为 \(0..n-1\) :对于任意的$ 0≤i<j≤n?1$ ,如果有 \(a[i]>a[j]\),那么 \(G\)中存在一条 \(i\)和 \(j\)之间的边.例如:\(A=\{1,3,4,0,2\}, G=\{(0,3),(1,

【CF 172K】k-Maximum Subsequence Sum

题意 给你一个长度为 \(n\) 的序列,有 \(q\) 组询问,每组询问给你 \(l,r,k\),让你在 \([l,r]\) 区间内选出 \(k\) 个不相交子段,使得这些子段包含的所有数的和最大. \(n,q\le 10^5,\space k\le 20\) 题解 这个 \(k=20\) 一看就很有问题啊 原文地址:https://www.cnblogs.com/scx2015noip-as-php/p/cf172k.html