首页 > 其他分享 >P3530 [POI2012]FES-Festival

P3530 [POI2012]FES-Festival

时间:2023-01-14 23:46:22浏览次数:47  
标签:P3530 cnt POI2012 700 tr head Festival int dis

// 题意:详细题意省略,要点是求所有人有多少种不同的取值
// 思路:差分约束最短路只能够求满足答案的最大解和最小解,但是对于取值却无法求解
//       可以发现,在一个强量通分量内,从任意点可以到达其他点,也就是说对于两个点,他们一定有一个 A+W1>=B 与 B+W2>=A 的双向限制, 即 W2 >=A-B>= -W1
//       又因为我们的边权只有1,-1,0  所以说我们找到 A-B 的最大差值即是一个scc的贡献
//       但是对于不同的SCC之间只有一个单项边,假设有两个scc A和B, 也就是只有一个单项限制 A-B<=W1 即 B-A>=W1
//       所以对于两个不同SCC我们可以取值使他们之间的贡献没有交集
//       所以最后的答案是所有scc的贡献之和
//       
//       另外这题要求A-B最大差值,也就是说我要求多源最短路,当然我用单源最短路求出来后 dis[a]-dis[b]也行
//       但是我们也可以直接用floyd,因为这题是个稀疏图(注意数据,这题n只有700,m达到了)
//       同时floyd判负环的方式可以看一下!!!!!!!!!
//
#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, m1, m2;
struct edge {
    int nxt, to, wt;
}tr[2 * N];
int head[N], cnt, dis[700][700], vis[700];
void add(int a, int b, int w) {
    tr[++cnt].to = b;
    tr[cnt].wt = w;
    tr[cnt].nxt = head[a];
    head[a] = cnt;
}
int main() {
    memset(dis, 0x3f, sizeof(dis));
    cin >> n >> m1 >> m2;
    for (int i = 1; i <= n; i++) dis[i][i] = 0;
    int a, b;
    for (int i = 1; i <= m1; i++) {
        cin >> a >> b;
        dis[a][b] = min(dis[a][b], 1);
        dis[b][a] = min(dis[b][a], -1);
    }
    for (int i = 1; i <= m2; i++) {
        cin >> a >> b;
        dis[b][a] = min(dis[b][a],0);
    }

    for (int k = 1; k <= n; k++)
        for (int i = 1; i <= n; i++)
                for (int j = 1; j <= n; j++)
                        dis[i][j] = min(dis[i][k] + dis[k][j], dis[i][j]);

    for (int i = 1; i <= n; i++) {
        if (dis[i][i] < 0) {
            cout << "NIE" << endl;
            return 0;
        }//判负环
    }
    
    int ans = 0;
    for(int i=1; i<=n; i++)
        if (!vis[i]) {
            vector<int> v;
            for(int j=1; j<=n; j++)
                if (dis[j][i] <= n && dis[i][j] <= n) {
                    v.push_back(j);
                    vis[j] = true;
                }
            int d = 0;
            for (auto p : v)
                for (auto q : v)
                    d = max(d, dis[p][q]);
            ans += d + 1;
            v.clear();
        }//dls的不用tarjan写法
    cout << ans << endl;
    return 0;
}



#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int n, m1, m2;
struct edge {
    int nxt, to, wt;
}tr[2 * N];
int head[N], cnt, dis[700][700], ans[700];
void add(int a, int b, int w) {
    tr[++cnt].to = b;
    tr[cnt].wt = w;
    tr[cnt].nxt = head[a];
    head[a] = cnt;
}
int dfn[N], low[N], idx, ins[N], ct, bel[N];
stack<int> stk;
vector<int> scc[700];
void dfs(int u) {
    dfn[u] = low[u] = ++idx;
    ins[u] = true;
    stk.push(u);
    for (int y = head[u]; y; y = tr[y].nxt) {
        int v = tr[y].to;
        if (!dfn[v]) dfs(v);
        if (ins[v]) low[u] = min(low[u], low[v]);
    }
    if (dfn[u] == low[u]) {
        ++ct;
        while (true) {
            int v = stk.top();
            scc[ct].push_back(v);
            ins[v] = false;
            bel[v] = ct;
            stk.pop();
            if (u == v) break;
        }
    }
}
int main() {
    memset(dis, 0x3f, sizeof(dis));
    memset(ans, -1, sizeof(ans));
    cin >> n >> m1 >> m2;
    for (int i = 1; i <= n; i++) dis[i][i] = 0;
    int a, b;
    for (int i = 1; i <= m1; i++) {
        cin >> a >> b;
        add(b, a, -1); add(a, b, 1);
        dis[a][b] = min(dis[a][b], 1);
        dis[b][a] = min(dis[b][a], -1);
    }
    for (int i = 1; i <= m2; i++) {
        cin >> a >> b;
        add(b, a, 0);
        dis[b][a] = min(dis[b][a], 0);
    }
    for (int i = 1; i <= n; i++)
        if (!dfn[i]) dfs(i);

    for (int k = 1; k <= n; k++)
        for (int i = 1; i <= n; i++)
            if (bel[i] == bel[k])
                for (int j = 1; j <= n; j++)
                    if (bel[i] == bel[j])
                        dis[i][j] = min(dis[i][k] + dis[k][j], dis[i][j]);

    for (int i = 1; i <= n; i++) {
        if (dis[i][i] < 0) {
            cout << "NIE" << endl;
            return 0;
        }//判负环
    }
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= n; j++)
            if (bel[i] == bel[j] && dis[i][j] <= n)//非常的关键,假如说在同一个强联通分量内 dis[i][j] 是被正常更新的,但 dis[j][i] 却不行,因为很可能只存在一条从i到j的单路
                ans[bel[j]] = max(ans[bel[j]], dis[i][j]);

    int tot = 0;
    for (int i = 1; i <= ct; i++) tot += ans[i];
    tot += ct;
    cout << tot << endl;
    return 0;
}

 

标签:P3530,cnt,POI2012,700,tr,head,Festival,int,dis
From: https://www.cnblogs.com/Aacaod/p/17052826.html

相关文章

  • P3537 [POI2012]SZA-Cloakroom 题解
    题目大意有\(n\)件物品,每件物品有三个属性\(a_i,b_i,c_i(a_i<b_i)\)。再给出\(q\)个询问,每个询问由非负整数\(m,k,s\)组成,问是否能够选出某些物品使得:对......
  • POI2012
    Q猜了个错的结论然后以为KMP写挂(首先显然我们发现可以固定前面的串不动,让后面的串转起来,具体的,如果前面的串可以分割成AB,则后面的串要求能分割成BA形式才算成功。也就是......
  • hud:Being a Good Boy in Spring Festival(nim博弈方法数计算)
    ProblemDescription一年在外父母时刻牵挂春节回家你能做几天好孩子吗寒假里尝试做做下面的事情吧陪妈妈逛一次菜场悄悄给爸爸买个小礼物主动地强烈地要求洗一次碗......
  • CODE FESTIVAL 2017 qual A
    ASnuke’sfavoriteYAKINIKU#include<bits/stdc++.h>usingnamespacestd;#define#define#define#define#define#define#define#define#define#define#define#define#def......
  • 洛谷 P3530 / bzoj2788【tarjan】【差分约束】
    判断是否有解可以使用差分约束。求解赛车手的成绩的取值可以使用Floyd。但是\(O(n^3)\)会TLE。可以先进行一次缩点。然后进行Floyd求出每一个连通块内的最长路径......
  • P3530 [POI2012]FES-Festival
    传送门思路对于第一种限制,我们连接\((x,y)=1\),\((y,x)=-1\)对于第二种限制,我们连接\((x,y)=0\)如果一个图只有第一种边,那么要么就是没有解(有环),要么答案就是点的个数......