首页 > 其他分享 >[USACO07DEC] Sightseeing Cows G

[USACO07DEC] Sightseeing Cows G

时间:2024-11-16 17:07:20浏览次数:1  
标签:Now int double USACO07DEC Graph Cows dis NowTo Sightseeing

算法

初看题面没有思路, 考虑使用数学语言表示

注意本题最重要的信息是发现路径为一个环

给你一张 \(n\) 点 \(m\) 边的有向图,第 \(i\) 个点点权为 \(F_i\) , 第 \(i\) 条边边权为 \(T_i\)

找一个环, 设环上的点组成的集合为 \(S\) , 环的边组成的集合为 \(E\) , 令

\[\frac{\sum_{u\in S}F_u}{\sum_{e\in E}T_e} \to max \]


这个形式与 \(0\)/\(1\) 分数规划很相似

考虑 \(0\)/\(1\) 分数规划的方式

\[\frac{ \sum_{u \in S} F_us_u} {\sum_{e\in E}T_es_u} \geq x \]

移项得,

\[f = \sum_{u \in S, e \in E} (F_u - xT_e)s_u \geq 0 \]

现在我们可以将图中的边权化为 \(F_u - xT_e\) , 然后只需要找到一个环, 看路径总长度是否大于 \(0\) , 二分是显然的

观察到这是一个典型的 \(\rm{spfa}\) 找正环的问题, 于是就可以打代码了

代码

实现上, 这里有一个类似于 \(\rm{Tarjan}\) 算法的问题, 边连接着两个点, 我们不好去判断 \(F_u, T_e\) 怎么改变边的权值

对于环, 我们只需要记录当前点出去的边为 \(T_e\) 即可, 反正最后会绕回去

所以也就简单了

#include <bits/stdc++.h>
#define int long long
const int MAXM = 5e3 + 1145;
const int MAXN = 1e3 + 30;
const double eps = 1e-5;

int n, m;
int Val[MAXN];

class Graph_Class
{
private:

public:
    struct node
    {
        int to; double w;
        int next;
    } Edge[MAXM];
    int Edge_Cnt = 0;
    int head[MAXN];
    void head_init() { for (int i = 0; i <= n; i++) { head[i] = -1; } }

    void init(){ head_init(); }

    void addedge(int u, int v, double w) {
        Edge[++Edge_Cnt].to = v;
        Edge[Edge_Cnt].w = w;
        Edge[Edge_Cnt].next = head[u];
        head[u] = Edge_Cnt;
    }
} Graph;

class Sol_Class
{
private:

    double dis[MAXN];
    int vis[MAXN];
    bool inq[MAXN];
    std::queue<int> Q;

    void init() {
        memset(dis, -0x3f, sizeof(dis));
        memset(vis, 0, sizeof(vis));
        while (!Q.empty()) Q.pop();
        memset(inq, false, sizeof(inq));
    }

    bool spfa(int Start, double x)
    {
        init();
        Q.push(Start), dis[Start] = 0, vis[Start]++, inq[Start] = true;

        while (!Q.empty())
        {
            int Now = Q.front();
            Q.pop();
            inq[Now] = false;

            for (int i = Graph.head[Now]; ~i; i = Graph.Edge[i].next) {
                int NowTo = Graph.Edge[i].to;
                double NowW = Val[Now] * 1.0 - x * Graph.Edge[i].w;
                if (dis[NowTo] < dis[Now] + NowW) {
                    dis[NowTo] = dis[Now] + NowW;

                    if (!inq[NowTo]) {
                        inq[NowTo] = true;
                        Q.push(NowTo);
                        vis[NowTo]++;
                        if (vis[NowTo] > n) return true;
                    }
                }
            }
        }
        return false;
    }

    /*只需要判断是否有正环即可, 有就可以返回 true*/
    bool check(double x) {
        return spfa(0, x);
    }

public:
    void solve()
    {
        double Left = 0, Right = 1024;
        double ans = -1;
        while (Right - Left > eps) {
            double Mid = Left + (Right - Left) / 2;
            if (check(Mid)) ans = Mid, Left = Mid;
            else Right = Mid;
        }

        printf("%.2lf", ans);
    }
} Sol;

signed main()
{
    scanf("%lld %lld", &n, &m);
    Graph.init();
    for (int i = 1; i <= n; i++)
        scanf("%lld", &Val[i]);
    for (int i = 1; i <= m; i++) {
        int u, v, w;
        scanf("%lld %lld %lld", &u, &v, &w);
        Graph.addedge(u, v, w);
    }

    /*建立超级源点*/
    for (int i = 1; i <= n; i++)
        Graph.addedge(0, i, 0);
    
    Sol.solve();

    return 0;
}

总结

初看题面没有思路, 考虑使用数学语言表示

注意超级源点会使 \(MAXM\) 变大

标签:Now,int,double,USACO07DEC,Graph,Cows,dis,NowTo,Sightseeing
From: https://www.cnblogs.com/YzaCsp/p/18549518

相关文章

  • C++基础语法实现写时复制CowString
    前言: CowString写时复制设计思路难点:通过下标访问字符串元素的基本思路重载[]运算符,在函数中直接返回该位置指针的解引用,但此时返回值为char类型,对于进行单个字符串修改的操作,如:str[1]='H';,无法处理赋值时的写时复制操作,只能通过输出流运算符输出char。解决方法:可以在Cow......
  • abc369E Sightseeing Tour
    有N个岛和M座双向桥,编号为i的桥连接岛U[i]和V[i],过桥耗时T[i],桥连接两不同的岛屿,两个岛之间可能会有多座桥。有Q组询问,每次询问给出K座桥,问从1号岛到N号岛的最少耗时,要求给出的K座桥分别至少经过1次。2<=N<=400;N-1<=M<=2E5;1<=U[i]<V[i]<=N;1<=T[i]<=1E9;1<=Q<=3000;1<=K[......
  • [USACO03Open] Lost Cows(二分加树状数组)
    #include<bits/stdc++.h>usingnamespacestd;#definexfirst#defineysecondtypedefpair<int,int>PII;typedeflonglongll;typedefunsignedlonglongull;typedefunsignedintuint;typedefvector<string>VS;typedefvector<int>......
  • 题解:[USACO07DEC] Sightseeing Cows G
    洛谷P2868题目大意有个nnn个点,mmm条边的有向图,点有点权,边有边......
  • [luoguAT_abc369_e] Sight[luoguAT_abc369_e]Sightseeing Tour
    题意给定一个包含\(N\)个点和\(M\)条无向边的带权图,保证图中没有自环,但可能包含重边。给出\(Q\)次查询,每次查询给出\(K\)条边\(B_1,B_2,\cdots,B_K\),要求求出从节点\(1\)到节点\(N\)且这\(K\)条边都至少经过一次的最短路(经过边的方向和顺序任意)。赛时Dijkstra......
  • 题解:AT_abc369_e [ABC369E] Sightseeing Tour 详细版
    题目大意给定一个NNN个点,MMM条边的无向图。其中边有边权。有......
  • 题解:洛谷 P10497 [USACO03Open] Lost Cows
    原题链接思路+算法首先,考虑读入到\(a_i\)时,如果要得到此时的最优解(指所有牛的编号不重不漏地覆盖\([1,i]\)的所有编号),对于第\(i\)头奶牛,因为在它前面有\(a_i\)头奶牛的编号小于它,所以第\(i\)头奶牛的编号应当为\(a_i+1\)。如果有一头新的奶牛\(i+1\)加入到这个......
  • 题解:P9944 [USACO21FEB] Comfortable Cows B
    思路由于每次输入\(x\)和\(y\)只改变其上下左右的值,所以每次只要更新其相邻的值即可。当某个位置相邻的奶牛数达到\(3\)时,舒适度加一。当某个位置相邻的奶牛数达到\(4\)时,舒适度减一。注意:每增加一头奶牛以后,如果该位置相邻正好有三头奶牛,则舒适度也要加一。ACcod......
  • [USACO5.1] 圈奶牛Fencing the Cows /【模板】二维凸包
    凸包,顾名思义,就是凸多边形包围,具体定义见OI-wiki(既是周长最小也是面积最小)有Graham算法和Andrew算法,后者精度更高常数更小(因为不涉及求角度)Andrew算法:1.将点排序(横坐标为第一关键字,纵坐标为第二关键字)2.从左到右维护上半部分,再从右到左维护下半部分。具体见OI-wiki。最后说的......
  • Cows in a Skyscraper G
    dfs版本#include<algorithm>#include<iostream>usingnamespacestd;constintN=2e1;intcat[N],cab[N];intn,w;intans;boolcmp(inta,intb){returna>b;}voiddfs(intnow,intcnt){if(cnt>=ans){re......