BZOJ 1922: [Sdoi2010]大陆争霸

二次联通门 : BZOJ 1922: [Sdoi2010]大陆争霸

/*
    BZOJ 1922: [Sdoi2010]大陆争霸

    最短路思路题
    带限制的转移
    _link[x] 记录的是当前城市有多少城市保护 

    记录两个距离
    一个是到当前点的最短路
    一个是最早能够进入当前点时间

    每次枚举当前点的必到点
    更新dis_2
    若都炸完后加入堆中 

    则答案就是 max (dis_1[N], dis_2[N]); 

*/
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>

#define Max 3050

void read (int &now)
{
    now = 0;
    register char word = getchar ();
    while (word < ‘0‘ || word > ‘9‘)
        word = getchar ();
    while (word >= ‘0‘ && word <= ‘9‘)
    {
        now = now * 10 + word - ‘0‘;
        word = getchar ();
    }
}

inline int max (int a, int b)
{
    return a > b ? a : b;
}

struct Edge_Data
{
    int to;
    int dis;
    int next;
};

struct Data_
{
    int Id;
    int dis;

    Data_ (int __Id, int __dis) : Id (__Id), dis (__dis) {};

    bool operator < (const Data_ &now) const
    {
        return this->dis > now.dis;
    }

    Data_ () {};
};

int N, M;
int number[Max];

int __link[Max][Max];
int count[Max];

int Answer;

class Dijkstra_Type
{
    private :

        Edge_Data edge[Max * 100];

        int Edge_Count ;
        int edge_list[Max];

        int dis_1[Max];
        int dis_2[Max];

        bool visit[Max];

    public :

        inline void Insert_Edge (int from, int to, int dis)
        {

            Edge_Count ++;
            edge[Edge_Count].to = to;
            edge[Edge_Count].next = edge_list[from];
            edge[Edge_Count].dis = dis;
            edge_list[from] = Edge_Count;

        }

        void Dijkstra (int Start, int End)
        {
            memset (dis_1, 0x3f, sizeof dis_1);

            std :: priority_queue <Data_> Queue;
            Queue.push (Data_ (Start, 0));
            dis_1[1] = 0;

            Data_ now;
            register int Maxn, res;
            register int pos;

            while (!Queue.empty ())
            {
                now = Queue.top ();
                Queue.pop ();

                if (visit[now.Id])
                    continue;

                visit[now.Id] = true;
                Maxn = max (dis_1[now.Id], dis_2[now.Id]);

                for (int i = edge_list[now.Id]; i; i = edge[i].next)
                    if (dis_1[edge[i].to] > Maxn + edge[i].dis)
                    {
                        dis_1[edge[i].to] = Maxn + edge[i].dis;
                        int res = max (dis_1[edge[i].to], dis_2[edge[i].to]);
                        if (!number[edge[i].to])
                            Queue.push (Data_ (edge[i].to, res));
                    }

                for (int i = 1; i <= count[now.Id]; i ++)
                {
                    pos = __link[now.Id][i];
                    number[pos] --;
                    dis_2[pos] = max (dis_2[pos], Maxn);
                    res = max (dis_1[pos], dis_2[pos]);
                    if (!number[pos])
                        Queue.push (Data_ (pos, res));
                }
            }
            Answer = max (dis_1[End], dis_2[End]);
        }
};

Dijkstra_Type Make;

int main (int argc, char *argv[])
{

    read (N);
    read (M);
    int x, y, z;

    for (int i = 1; i <= M; i ++)
    {
        read (x);
        read (y);
        read (z);

        if (x != y)
            Make.Insert_Edge (x, y, z);
    }

    for (int i = 1; i <= N; i ++)
    {
        read (number[i]);
        for (int pos = 1, x; pos <= number[i]; pos ++)
        {
            read (x);
            __link[x][++ count[x]] = i;
        }
    }

    Make.Dijkstra (1, N);

    printf ("%d", Answer);
    return 0;
}
时间: 2024-10-08 10:29:16

BZOJ 1922: [Sdoi2010]大陆争霸的相关文章

bzoj 1922 [Sdoi2010]大陆争霸(最短路变形)

Description 在一个遥远的世界里有两个国家:位于大陆西端的杰森国和位于大陆东端的 克里斯国.两个国家的人民分别信仰两个对立的神:杰森国信仰象征黑暗和毁灭 的神曾·布拉泽,而克里斯国信仰象征光明和永恒的神斯普林·布拉泽. 幻想历 8012年 1月,杰森国正式宣布曾·布拉泽是他们唯一信仰的神,同 时开始迫害在杰森国的信仰斯普林·布拉泽的克里斯国教徒. 幻想历 8012年 3月2日,位于杰森国东部小镇神谕镇的克里斯国教徒发动 起义. 幻想历 8012年 3月7日,神谕镇的起义被杰森国大军以残

bzoj 1922: [Sdoi2010]大陆争霸 带限制最短路

题意:有n个点和m条道路.有一些点必须经过了某些点后才能到达,问从起点到达终点的最短时间. 分析:带限制的最短路. 设d1[x]为可以进入点x的时间,d2[x]为到达点x的时间,s[x]为点x被多少个点保护. 一开始以为d1和d2是有关联的,也就是要通过d1来推出某些d2,然后想破脑袋都想不出(其实也没那么夸张啦).后来看了题解才发现这两个可以分开求,然后进入点x的实际时间为max(d1[x],d2[x]). 然后跑dijkstra,每次找到一个d2最小且s[x]=0的点,然后更新与这个点相连的

1922: [Sdoi2010]大陆争霸|dijkstra

最短路大法好.Orz黄学长 设d1[x],d2[x]为城市x的到达时间,可进入时间 max(d1[x],d2[x])为真实的进入时间 d[x]记录城市x被多少个城市保护 每次堆中取出一个真实进入时间最小的城市 更新它所通往的城市的d1,保护城市的d2 保护城市的d–1 若d=0,则可入堆 复杂度(n+m)log2n 黄学长写的比较清楚了,似乎很多人都用了矩阵存图的样子,怪不得一遍卡进第一页 #include<iostream> #include<algorithm> #includ

AC日记——[SDOI2010]大陆争霸 洛谷 P3690

[SDOI2010]大陆争霸 思路: dijkstra模板: 代码: #include <bits/stdc++.h> using namespace std; #define maxn 3005 #define ll long long #define maxm 70002<<2 #define INF 1e13 struct NodeType { ll id,dis; bool operator<(const NodeType pos)const { return dis

BZOJ1922 [Sdoi2010]大陆争霸 【最短路】

题目 在一个遥远的世界里有两个国家:位于大陆西端的杰森国和位于大陆东端的 克里斯国.两个国家的人民分别信仰两个对立的神:杰森国信仰象征黑暗和毁灭 的神曾·布拉泽,而克里斯国信仰象征光明和永恒的神斯普林·布拉泽. 幻想历 8012年 1月,杰森国正式宣布曾·布拉泽是他们唯一信仰的神,同 时开始迫害在杰森国的信仰斯普林·布拉泽的克里斯国教徒. 幻想历 8012年 3月2日,位于杰森国东部小镇神谕镇的克里斯国教徒发动 起义. 幻想历 8012年 3月7日,神谕镇的起义被杰森国大军以残酷手段镇压. 幻想

Dijkstra【P2446】 [SDOI2010]大陆争霸

Background 在一个遥远的世界里有两个国家:位于大陆西端的杰森国和位于大陆东端的克里斯国.两个国家的人民分别信仰两个对立的神:杰森国信仰象征黑暗和毁灭的神曾·布拉泽,而克里斯国信仰象征光明和永恒的神斯普林·布拉泽. 幻想历8012年1月,杰森国正式宣布曾·布拉泽是他们唯一信仰的神,同时开始迫害在杰森国的信仰斯普林·布拉泽的克里斯国教徒. 幻想历8012年3月2日,位于杰森国东部小镇神谕镇的克里斯国教徒发动起义. 幻想历8012年3月7日,神谕镇的起义被杰森国大军以残酷手段镇压. 幻想历8

BZOJ1922 SDOI2010 大陆争霸 最短路

题意:给定一个图,图中有保护关系(u,v)表示到v之前必须先到一次u,求从1到N的最短路 题解: 定义d1[i]为直接到达i的最短距离,这个的更新和普通的Dijkstra一样 定义d2[i]为解除i的所有保护的最短距离(不一定要在i结束),这个更新起来很简单,每经过一个节点就将其所控制的城市的发生器数全部--,没有发生器的城市直接用当前的距离更新即可. 最后答案显然就是max(d1[N],d2[N]) #include <queue> #include <vector> #incl

BZOJ1922:[Sdoi2010]大陆争霸

炕帮饨 没耜氖 炙热火焰的脑海中就不由自主地想起来了昨天 胯炙攫饵 鲨垆蹲嘌 延矜雯皖 著な价 ⒖蹇劳俳 椽枳饽胃 鼓镆腹箨 荭孰卩 绲面硪座 季芜虼禀 蝻轿骅 答丐} 埃根觌掼 玻畸滁陕 鲺吓铟期 臼ザ 愎桓 缶鄯╁狮 没没笑什么赶紧否认也只是想想这傅盈可不像自己乡下那 涠掂 藤 せλ ネ护冉咙 具妄倬叻 咐躐佘烁 ο鼐委餐 彳Ο袷ダ 弗继髻 葺橙蛋 葫Ф膝绷 嚯兴验 渌魏益靓 敝斐倾箔 肆?岢 庶蚜翱 桔眍 茜蔷 疗鄹抓 摔邝蛇摇 糖仨钸

[SDOI2010]大陆争霸

嘟嘟嘟 首先可以知道,对于在哪个时候攻占一个城市,应该是他的最短到达时间和最早进入时间的最大值(max(d1[i], d2[i])). 最短到达时间:就是朴素的最短路d1[i]. 最早进入时间:设所有到达有他的结界发生器的城市为j,那么应该是在所有最短时间中取max,作为d2[i]. 于是就可以用dijkstra写了. 每一次成功更新节点 i 的d1时,就更新所有 i 能控制的节点 j 的d2. 我们还要记录每一个节点的入度,代表控制它的城市有几个,然后如果他的d2被更新了一次,就减1,若果为0