联合训练图论场

原创 2016年05月31日 21:15:00

联合训练图论场题解报告

传送门


A.Euler

题意:略

分析:

这题主要是先掌握欧拉通路的概念,然后是如何判断图是否存在欧拉通路。
欧拉通路:通过图中每条边且只通过一次,并且经过每一顶点的通路。
欧拉回路:通过图中每条边且只通过一次,并且经过每一顶点的回路。
无向图:
    欧拉通路:连通图+只存在0个或者两个度数为奇数的点。
    欧拉回路:连通图+所有节点的度数均为偶数。
有向图:
    欧拉通路:连通图+(所有点的入度=出度 || 出两个点之外其他点的入度=出度,一个点的入度-出度=1,一个点的出度-入度=1)。
ii e[500*500];
int in[510], out[510];//indegree,outdegree
int f[510];//判断是否连通
int find(int x) {
    return f[x] == -1 ? x : f[x] = find(f[x]);
}
int main(int argc, const char * argv[])
{   
    // freopen("in.txt","r",stdin);
    // freopen("out.txt","w",stdout);
    // clock_t _ = clock();

    int t, n, m;
    scanf("%d", &t);
    while(t--) {
        scanf("%d%d", &n, &m);
        for (int i = 0;i < m;++i)
            scanf("%d%d", &e[i].first, &e[i].second);
        memset(in, 0,sizeof in);
        memset(out, 0,sizeof out);
        memset(f, -1,sizeof f);
        int cnt = 0;
        for (int i = 0;i < m;++i) {
            in[e[i].first]++;
            in[e[i].second]++;
            int t1 = find(e[i].first);
            int t2 = find(e[i].second);
            if (t1 != t2) f[t1] = t2;
        }
        int o=0;
        for (int i = 1;i <= n;++i) {
            find(i);
            if (f[i] == -1) o++;
        }//o == 说明图连通
        for (int i = 1;i <= n;++i)
            if (in[i] & 1) cnt++;
        if (cnt == 0 || cnt == 2) {
            if (o == 1) printf("Yes");
            else printf("No");
        }else printf("No");
        printf(" ");


        memset(in, 0,sizeof in);
        memset(f, -1,sizeof f);
        cnt = 0;
        for (int i = 0;i < m;++i) {
            out[e[i].first]++;
            in[e[i].second]++;
        }
        if (o > 1) puts("No");
        else {
            vector<int> vec;
            for (int i = 1;i <= n;++i) {
                if (in[i] != out[i]) vec.push_back(i);
            }
            if (vec.size() != 2 && vec.size() != 0) puts("No");
            else {
                if (vec.size() == 0) {
                    puts("Yes");
                    continue;
                }
                int u = vec[0], v = vec[1];
                if (in[u] - out[u] == 1 && in[v] - out[v] == -1) puts("Yes");
                else if (in[u] - out[u] == -1 && in[v] - out[v] == 1) puts("Yes");
                else puts("No");
            }
        }
    }
    // printf("\nTime cost: %.2fs\n", 1.0 * (clock() - _) / CLOCKS_PER_SEC);
    return 0;
}

B.-0你的电脑炸了

题意

判断给出的图是否合法。

分析

4*4的格子中,每个位置会出现指定的某些数字,但是由于覆盖的作用,只会看见最上面的一个,其他的被压在了下面。A覆盖了B,B覆盖了A,这样是显然不成立的,这题就是判断是否会出现相互覆盖的情况,拓普排序。
ps:初始化的表要仔细打。。。
vector<int> have[5][5];
int a[5][5];
int in[10];
vector<int> G[10];
void init() {
    have[1][1].push_back(1);
    have[1][2].push_back(1), have[1][2].push_back(2);
    have[1][3].push_back(2), have[1][3].push_back(3);
    have[1][4].push_back(3);

    have[2][1].push_back(1), have[2][1].push_back(4);
    have[2][2].push_back(1), have[2][2].push_back(2), have[2][2].push_back(4), have[2][2].push_back(5);
    have[2][3].push_back(2), have[2][3].push_back(3), have[2][3].push_back(5), have[2][3].push_back(6);
    have[2][4].push_back(3), have[2][4].push_back(6);

    have[3][1].push_back(4), have[3][1].push_back(7);
    have[3][2].push_back(4), have[3][2].push_back(5), have[3][2].push_back(7), have[3][2].push_back(8);
    have[3][3].push_back(5), have[3][3].push_back(6), have[3][3].push_back(8), have[3][3].push_back(9);
    have[3][4].push_back(6), have[3][4].push_back(9);

    have[4][1].push_back(7);
    have[4][2].push_back(7), have[4][2].push_back(8);
    have[4][3].push_back(8), have[4][3].push_back(9);
    have[4][4].push_back(9);
}
void done(int u,int i, int j) {
    for (int k = 0;k < have[i][j].size();++k) {
        int v = have[i][j][k];
        if (u == v) continue;
        G[u].push_back(v);
        in[v]++;
    }
}
void getmap() {
    for (int i = 1;i <= 9;++i) {
        G[i].clear();
        in[i] = 0;
    }
    for (int i = 1;i <= 4;++i) {
        for (int j = 1;j <= 4;++j)
            done(a[i][j], i, j);
    }
}
void solve() {
    getmap();
    queue<int> que;
    for (int i = 1;i <= 9;++i) {
        if (in[i] == 0) {
            que.push(i);
        }
    }
    while(!que.empty()) {
        int u = que.front();
        que.pop();
        for (int i = 0;i < G[u].size();++i) {
            int v = G[u][i];
            if (--in[v] == 0) {
                que.push(v);
            }
        }
    }
    bool ok = true;
    for (int i = 1;i <= 9;++i)
        if (in[i] > 0) ok = false;
    if (ok) puts("Lucky dog!");
    else puts("BOOM!");
}
int main(int argc, const char * argv[])
{   
    // freopen("in.txt","r",stdin);
    // freopen("out.txt","w",stdout);
    // clock_t _ = clock();

    init();
    int T;
    cin >> T;
    while(T--) {
        for (int i = 1;i <= 4;++i) {
            for (int j = 1;j <= 4;++j)
                scanf("%d", &a[i][j]);
        }
        solve();
    }

    // printf("\nTime cost: %.2fs\n", 1.0 * (clock() - _) / CLOCKS_PER_SEC);
    return 0;
}

C.寻找fly真迹

题意

分析

首先用补图还是很容易想到的(毕竟正着搞相对复杂了)。建立补图之后很容易就想到了二分图染色,最后判断是否成立。
const int maxn = 5e2 + 10;
int n, m;
int col[maxn];
vector<int> G[maxn];
int g[maxn][maxn];
bool dfs(int u,int color) {
    col[u] = color;
    for (int i = 0;i < G[u].size();++i) {
        int v = G[u][i];
        if (col[u] == col[v]) return false;
        if (!col[v] && !dfs(v, -color)) return false;
    }
    return true;
}
int main(int argc, const char * argv[])
{    
    // freopen("in.txt","r",stdin);
    // freopen("out.txt","w",stdout);
    // clock_t _ = clock();

    int t;
    cin >> t;
    while(t--) {
        scanf("%d%d", &n, &m);
        memset(g, 0,sizeof g);
        int u, v;
        for (int i = 1;i <= m;++i) {
            scanf("%d%d", &u, &v);
            g[u][v] = g[v][u] = 1;
        }
        for (int i = 1;i <= n;++i) {
            G[i].clear();
            for (int j = 1;j <= n;++j)
                if (i != j && !g[i][j]) G[i].push_back(j);
        }
        bool yes = true;
        memset(col, 0,sizeof col);
        for (int i = 1;i <= n;++i) {
            if (!col[i] && G[i].size() && !dfs(i, 1)) {
                yes=false;
            }
        }
        for (int i = 1;i <= n;++i) {
            for (int j = 1;j <= n;++j) {
                if (i == j) continue;
                if (g[i][j] && col[i]*col[j]<0)yes=false;
                if (!g[i][j] && col[i]*col[j]>=0)yes=false;
            }
        }
        if (yes) puts("Yes");
        else puts("No");
    }

    // printf("\nTime cost: %.2fs\n", 1.0 * (clock() - _) / CLOCKS_PER_SEC);
    return 0;
}

D.一食堂or二食堂,it’s a question

题意

好懂,可能就“使得任意两人走过的距离加上二人所在食堂的距离的最大值最小”这句话需要解释下。任意两个人A, B 如果在同一个食堂的话就是他两个走过的距离和,如果不在同一个食堂就再加上两个食堂之间的距离。

分析

求最大最小,显然二分结果值。然后根据二分值建图判断可行性。
我们可以用bool值表示每个人的选择。对于第i个人而言,i表示其选择第一食堂,i+N表示其选择二食堂。
<1> 相互憎恨的两个人x,y
必然建立四条边(x,y+N), (y,x+N),(x+N,y),(y+N,x)。表示两个选择不同的食堂。
<2> 相互喜欢的两个人x,y
必然建立四条边(x,y),(y,x),(x+N,y+N),(y+N,x+N)表示两个人选择同一个食堂。
<3> 对于人意的两个人x,y
这里就看代码了。。。
/*****************************************
Author      :Crazy_AC(JamesQi)
Time        :2016
File Name   :
                   _ooOoo_
                  o8888888o
                  88" . "88
                  (| -_- |)
                  O\  =  /O
               ____/`---'\____
             .'  \|     |//  `.
            /  \|||  :  |||//  \
           /  _||||| -:- |||||-  \
           |   | \\  -  /// |   |
           | \_|  ''\---/''  |   |
           \  .-\__  `-`  ___/-. /
         ___`. .'  /--.--\  `. . __
      ."" '<  `.___\_<|>_/___.'  >'"".
     | | :  `- \`.;`\ _ /`;.`/ - ` : | |
     \  \ `-.   \_ __\ /__ _/   .-` /  /
======`-.____`-.___\_____/___.-`____.-'======
                   `=---='
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         佛祖保佑       永无BUG
*****************************************/
// #pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <climits>
using namespace std;
#define MEM(x,y) memset(x, y,sizeof x)
#define pk push_back
#define lson rt << 1
#define rson rt << 1 | 1
#define bug cout << "BUG HERE\n"
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> ii;
typedef pair<ii,int> iii;
const double eps = 1e-8;
const double pi = 4 * atan(1);
const int inf = 1 << 30;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
int nCase = 0;
int dcmp(double x){//精度正负、0的判断
    if (fabs(x) < eps) return 0;
    return x < 0?-1:1;
}
inline int read(){
    char c = getchar();
    while (!isdigit(c)) c = getchar();
    int x = 0;
    while (isdigit(c)) {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x;
}
const int maxn = 2010;
struct Edge{
    int to, nxt;
    Edge() {}
    Edge(int to,int nxt) {
        this->to = to;
        this->nxt = nxt;
    }
}edges[maxn*maxn];
int N, A, B;
int head[maxn], ecnt;
void add(int u,int v) {
    edges[ecnt] = Edge(v, head[u]), head[u] = ecnt++;
}
int dfn[maxn], low[maxn], depth;
bool in[maxn];
stack<int> st;
int belong[maxn];
int block;
void tarjan(int u) {
    dfn[u] = low[u] = ++depth;
    in[u] = true;
    st.push(u);

    for (int i = head[u]; ~i;i = edges[i].nxt) {
        int v = edges[i].to;
        if (dfn[v] == -1) {
            tarjan(v);
            low[u] = min(low[u], low[v]);
        }else if (in[v]) low[u] = min(low[u], dfn[v]);
    }

    if (dfn[u] == low[u]) {
        block++;
        while(true) {
            int x = st.top();
            st.pop();
            in[x] = false;
            belong[x] = block;
            if (x == u) break;
        }
    }
}
struct point {
    int x, y;
    void read() {
        scanf("%d%d", &x, &y);
    }
}p[maxn], hate[maxn], like[maxn], s1, s2;
int dis[maxn][maxn];
inline int dist(point& a,point& b) {//曼哈顿距离
    return abs(a.x - b.x) + abs(a.y - b.y);
}
bool ok() {
    depth = block = 0;
    memset(dfn, -1,sizeof dfn);
    for (int i = 1;i <= 2*N;++i)
        if (dfn[i] == -1) tarjan(i);
    for (int i = 1;i <= N;++i)
        if (belong[i] == belong[i+N]) return false;
    return true;
}

void getmap(int limit) {
    ecnt = 0;
    memset(head, -1,sizeof head);
    for (int i = 1;i <= A;++i) {
        add(hate[i].x, hate[i].y + N);
        add(hate[i].y, hate[i].x + N);

        add(hate[i].x + N, hate[i].y);
        add(hate[i].y + N, hate[i].x);
    }

    for (int i = 1;i <= B;++i) {
        add(like[i].x, like[i].y);
        add(like[i].y, like[i].x);

        add(like[i].x + N, like[i].y + N);
        add(like[i].y + N, like[i].x + N);
    }

    for (int i = 1;i <= N;++i) {
        for (int j = i + 1;j <= N;++j) {
            if (dis[i][N+1] + dis[j][N+1] > limit) {//不能一同食堂
                add(i, j + N);
                add(j, i + N);
            }
            if (dis[i][N+2] + dis[j][N+2] > limit) {
                add(i + N, j);
                add(j + N, i);
            }
            if (dis[i][N+1] + dis[j][N+2] + dis[N+1][N+2] > limit) {
                add(i, j);
                add(j+N, i+N);
            }
            if (dis[i][N+2] + dis[j][N+1] + dis[N+1][N+2] > limit) {
                add(i+N,j+N);
                add(j, i);
            }
        }
    }
}
int main(int argc, const char * argv[])
{   
    // freopen("in.txt","r",stdin);
    // freopen("out.txt","w",stdout);
    // clock_t _ = clock();

    int T_T;
    scanf("%d", &T_T);
    while(T_T--) {
        scanf("%d%d%d", &N, &A, &B);
        s1.read(), s2.read();
        dis[N+1][N+2] = dist(s1, s2);
        for (int i = 1;i <= N;++i)
        {
            p[i].read();
            dis[i][N+1] = dist(p[i], s1);
            dis[i][N+2] = dist(p[i], s2);
        }
        for (int i = 1;i <= A;++i) 
            hate[i].read();
        for (int i = 1;i <= B;++i)
            like[i].read();
        int low = 0, high = 50000000;
        int ans = -1;
        while(low <= high) {
            int mid = (low + high) / 2;
            getmap(mid);
            if (ok()) {
                ans = mid;
                high = mid - 1;
            }else low = mid + 1;
        }
        printf("%d\n", ans);
    }

    // printf("\nTime cost: %.2fs\n", 1.0 * (clock() - _) / CLOCKS_PER_SEC);
    return 0;
}

E.Division

题意

分析

套路,缩点+匹配
const int N = 5000 + 10;
const int M = 100000 + 10;
int n, m;
int head[N], pnt[M], nxt[M], cnt;
void init() {
    memset(head, -1,sizeof head);
    cnt = 0;
}
void addedge(int u,int v) {
    pnt[cnt] = v, nxt[cnt] = head[u],head[u] = cnt++;
}
int dfn[N], low[N], belong[N];
int Times;
stack<int> st;
int scc;
void Tarjan(int u) {
    dfn[u] = low[u] = ++Times;
    st.push(u);
    for (int i = head[u];~i;i = nxt[i]) {
        int v = pnt[i];
        if (!dfn[v]) {
            Tarjan(v);
            low[u] = min(low[u], low[v]);
        }else if (!belong[v]) low[u] = min(low[u], dfn[v]);
    }
    if (dfn[u] == low[u]) {
        ++scc;
        while(true) {
            int x = st.top();
            st.pop();
            belong[x] = scc;
            if (x == u) break;
        }
    }
}
vector<int> G[N];


int linker[N];
bool vis[N];

bool dfs(int u) {
    for (int i = 0;i < G[u].size();++i) {
        int v = G[u][i];
        if (vis[v]) continue;
        vis[v] = true;
        if (linker[v] == -1 || dfs(linker[v])) {
            linker[v] = u;
            return true;
        }
    }
    return false;
}

int Hungary(){
    int ans = 0;
    memset(linker, -1,sizeof linker);
    for (int i = 1;i <= scc;++i) {
        memset(vis, false,sizeof vis);
        if (dfs(i)) ans++;
    }
    return ans;
}

int main()
{   
    // freopen("in.txt","r",stdin);
    // freopen("out.txt","w",stdout);
    int t;
    scanf("%d",&t);
    while(t--) {
        scanf("%d%d",&n,&m);
        init();
        int u, v;
        for (int i = 1;i <= m;++i) {
            scanf("%d%d",&u,&v);
            addedge(u, v);
        }
        memset(dfn, 0,sizeof dfn);
        memset(belong, 0,sizeof belong);
        scc = Times = 0;
        for (int i = 1;i <= n;++i) G[i].clear();
        for (int i = 1;i <= n;++i) if (!dfn[i]) Tarjan(i);
        for (int i = 1;i <= n;++i) {
            for (int j = head[i];~j;j = nxt[j]) {
                int v = pnt[j];
                if (belong[i] != belong[v]) {
                    G[belong[i]].push_back(belong[v]);
                }
            }
        }
        printf("%d\n", scc - Hungary());
    }
    return 0;
}

F.meixiuxiu学图论

题意

求所有环中的最大边权的最小值。

分析

可以两种做法。
1.二分结果然后scc.
2.最小生成树的应用.
说第二种吧。。。把边排序,然后合并第一个形成的环的最后一天边就是答案。
const int maxn = 5e5 + 10;
const int maxm = 2e6 + 10;
struct Edge {
    int u, v, c;
    Edge() {}
    Edge(int u,int v,int c) {
        this->u = u;
        this->v = v;
        this->c = c;
    }
    bool operator < (const Edge& rhs) const {
        return c < rhs.c;
    }
    void read() {
        scanf("%d%d%d", &u, &v, &c);
    }
}e[maxm];
int f[maxn];
int find(int x) {
    return f[x] == -1?x : f[x] = find(f[x]);
}
int main(int argc, const char * argv[])
{    
    // freopen("in.txt","r",stdin);
    // freopen("out.txt","w",stdout);
    // clock_t _ = clock();

    int n , m;
    int t;
    scanf("%d", &t);
    while(t--) {
        scanf("%d%d", &n, &m);
        for (int i = 0;i < m;++i)
            e[i].read();
        sort(e,e+m);
        memset(f, -1,sizeof f);
        int ans = -1;
        for (int i = 0;i < m;++i) {
            int t1 = find(e[i].u);
            int t2 = find(e[i].v);
            if (t1 != t2) {
                f[t1] = t2;
            }else if (ans == -1) ans = e[i].c;
        }
        if (ans == -1) puts("No solution!");
        else printf("%d\n", ans);
    }

    // printf("\nTime cost: %.2fs\n", 1.0 * (clock() - _) / CLOCKS_PER_SEC);
    return 0;
}

G.最短路

题意

分析

问的是最短路的条数,且任意两条路不重复。首先每条路径都是最短的,所以就建立最短路树。然后就是最大流算法了。并附上最大流模版。。。
const int maxn = 1010;
vector<ii> G[2][maxn];//v, cost
int n, m;
int dis1[maxn], dis2[maxn], in[maxn];
void spfa(int s,int t,int* d, int o) {
    for (int i = 1;i <= n;++i)
        d[i] = INF;
    memset(in, 0,sizeof in);
    d[s] = 0;
    queue<int> que;
    que.push(s);
    while(!que.empty()) {
        int u = que.front();
        que.pop();
        in[u] = 0;
        for (int i = 0;i < G[o][u].size();++i) {
            int v = G[o][u][i].first;
            int cost = G[o][u][i].second;
            if (d[v] > d[u] + cost) {
                d[v] = d[u] + cost;
                if (in[v] == 0) {
                    in[v] = 1;
                    que.push(v);
                }
            }
        }
    }
}
struct Edge{
    int from, to, cap, flow;
    Edge(){}
    Edge(int from,int to,int cap,int flow):from(from),to(to),cap(cap),flow(flow){}
};
struct ISAP{
    int p[maxn], num[maxn], cur[maxn], d[maxn];
    int s, t, n, m;
    bool vis[maxn];

    vector<int> G[maxn];
    vector<Edge> edges;

    void init(int n) {
        this->n = n;
        for (int i = 0;i <= n;++i) {
            G[i].clear();
            d[i] = INF;
        }
        edges.clear();
    }

    void addedge(int from,int to,int cap) {
        edges.push_back(Edge(from, to, cap, 0));
        edges.push_back(Edge(to, from, 0, 0));
        m = (int)edges.size();
        G[from].push_back(m - 2);
        G[to].push_back(m - 1);
    }

    bool bfs() {
        memset(vis, false,sizeof vis);

        queue<int> que;
        d[t] = 0;
        vis[t] = true;
        que.push(t);

        while(!que.empty()) {
            int u = que.front();
            que.pop();

            for (int i = 0;i < G[u].size();++i) {
                Edge& e = edges[G[u][i]^1];
                if (e.cap > e.flow && !vis[e.from]) {
                    vis[e.from] = true;
                    d[e.from] = d[u] + 1;
                    que.push(e.from);
                }
            }
        }
        return vis[s];
    }

    int Augment() {
        int u = t, flow = INF;
        while(u != s) {
            Edge& e = edges[p[u]];
            flow = min(flow, e.cap - e.flow);
            u = edges[p[u]].from;
        }

        u = t;
        while(u != s) {
            edges[p[u]].flow += flow;
            edges[p[u]^1].flow -= flow;
            u = edges[p[u]].from;
        }
        return flow;
    }

    int MaxFlow(int s,int t) {
        this->s = s,this->t = t;
        int ret = 0;
        bfs();
        if (d[s] >= n) return 0;

        memset(num, 0,sizeof num);
        memset(cur, 0,sizeof cur);
        for (int i = 0;i < n;++i) {
            if (d[i] < INF) num[d[i]]++;
        }
        int u = s;

        while(d[s] < n) {

            if (u == t) {
                ret += Augment();
                u = s;
            }

            bool ok = false;
            for (int i = cur[u];i < G[u].size();++i) {
                Edge& e = edges[G[u][i]];
                if (e.cap > e.flow && d[u] == d[e.to] + 1) {
                    ok = true;
                    p[e.to] = G[u][i];
                    cur[u] = i;
                    u = e.to;
                    break;
                }
            }

            if (!ok) {
                int Min = n - 1;
                for (int i = 0;i < G[u].size();++i) {
                    Edge& e = edges[G[u][i]];
                    if (e.cap > e.flow) Min = min(Min, d[e.to]);
                }
                if (--num[d[u]] == 0) break;
                num[d[u] = Min + 1]++;
                cur[u] = 0;
                if (u != s) u = edges[p[u]].from;
            }
        }
        return ret;
    }
}solve;
int main(int argc, const char * argv[])
{   
    // freopen("in.txt","r",stdin);
    // freopen("out.txt","w",stdout);
    // clock_t _ = clock();

    int t;
    cin >> t;
    while(t--) {
        scanf("%d%d", &n, &m);
        for (int i = 1;i <= n;++i)
            G[0][i].clear(), G[1][i].clear();
        int u, v, c;
        for (int i = 1;i <= m;++i) {
            scanf("%d%d%d", &u, &v, &c);
            G[0][u].push_back(ii(v, c));
            G[1][v].push_back(ii(u, c));
        }
        int st, ed;
        scanf("%d%d", &st, &ed);
        spfa(st, ed, dis1, 0);
        spfa(ed, st, dis2, 1);
        int limit = dis1[ed];
        if (limit == INF) {
            printf("%d\n", 0);
            continue;
        }

        solve.init(n);

        for (int i = 1;i <= n;++i) {
            for (int j = 0;j < G[0][i].size();++j) {
                int k = G[0][i][j].first;
                if (dis1[i] != INF && dis2[k] != INF && dis1[i] + dis2[k] + G[0][i][j].second == limit) {
                    solve.addedge(i, k, 1);
                }
            }
        }
        int ans = solve.MaxFlow(st, ed);
        printf("%d\n", ans);
    }

    // printf("\nTime cost: %.2fs\n", 1.0 * (clock() - _) / CLOCKS_PER_SEC);
    return 0;
}

H.NightMare2

题意

从1号点到n号点在k的时间内逃出去的前提下,能带走的最大价值珠宝。

分析

又是一种套路。二分答案,然后跑最短路,看能不能逃出去。
/*****************************************
Author      :Crazy_AC(JamesQi)
Time        :2016
File Name   :
                   _ooOoo_
                  o8888888o
                  88" . "88
                  (| -_- |)
                  O\  =  /O
               ____/`---'\____
             .'  \|     |//  `.
            /  \|||  :  |||//  \
           /  _||||| -:- |||||-  \
           |   | \\  -  /// |   |
           | \_|  ''\---/''  |   |
           \  .-\__  `-`  ___/-. /
         ___`. .'  /--.--\  `. . __
      ."" '<  `.___\_<|>_/___.'  >'"".
     | | :  `- \`.;`\ _ /`;.`/ - ` : | |
     \  \ `-.   \_ __\ /__ _/   .-` /  /
======`-.____`-.___\_____/___.-`____.-'======
                   `=---='
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         佛祖保佑       永无BUG
*****************************************/
// #pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <climits>
using namespace std;
#define MEM(x,y) memset(x, y,sizeof x)
#define pk push_back
#define lson rt << 1
#define rson rt << 1 | 1
#define bug cout << "BUG HERE\n"
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> ii;
typedef pair<ii,int> iii;
const double eps = 1e-8;
const double pi = 4 * atan(1);
const long long inf = 1e20 + 10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
int nCase = 0;
int dcmp(double x){//精度正负、0的判断
    if (fabs(x) < eps) return 0;
    return x < 0?-1:1;
}
inline int read(){
    char c = getchar();
    while (!isdigit(c)) c = getchar();
    int x = 0;
    while (isdigit(c)) {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x;
}
const int maxn = 1e4 + 10;
struct Edge {
    int v, limit, cost;
    Edge() {}
    Edge(int v,int limit, int cost) {
        this->v = v;
        this->limit = limit;
        this->cost = cost;
    }
};
vector<Edge> G[maxn];
int n, m, k;
struct node {
    int p;
    long long cost;
    node() {}
    node(int p,long long cost) {
        this->p = p;
        this->cost = cost;
    }
    bool operator < (const node& rhs) const {//小的优先
        return cost > rhs.cost;
    }
};
long long dis[maxn];
int vis[maxn];
bool solve(int limit) {
    // memset(dis, INF,sizeof dis);
    for (int i = 1;i <= n;++i)
        dis[i] = inf;
    memset(vis, 0,sizeof vis);
    dis[1] = 0;
    priority_queue<node> que;
    que.push(node(1, 0));
    while(!que.empty()) {
        node temp = que.top();
        que.pop();
        int u = temp.p;
        if (vis[u]) continue;
        vis[u] = 1;
        for (int i = 0;i < G[u].size();++i) {
            if (G[u][i].limit < limit) continue;
            int v = G[u][i].v;
            long long cost = G[u][i].cost;
            if (dis[v] > dis[u] + cost) {
                dis[v] = dis[u] + cost;
                que.push(node(v, dis[v]));
            }
        }
    }
    return dis[n] <= k;
}


int main(int argc, const char * argv[])
{   
    freopen("in.txt","r",stdin);
    // freopen("out.txt","w",stdout);
    // clock_t _ = clock();

    int t;
    scanf("%d",&t);
    while(t--) {
        scanf("%d%d%d", &n, &m, &k);
        for (int i = 1;i <= n;++i)
            G[i].clear();
        int u, v, l, c;
        int high = 0, low = INF;
        for (int i = 1;i <= m;++i) {
            scanf("%d%d%d%d", &u, &v, &l, &c);
            G[u].push_back(Edge(v, l, c));
            G[v].push_back(Edge(u, l, c));
            high = max(high, l);
            low = min(low, l);
        }
        int ans = -1;
        while(low <= high) {
            int mid = (high + low) >> 1;
            if (solve(mid)) {
                low = mid + 1;
                ans = mid;
            }else high = mid - 1;
        }
        if (solve(low)) ans = max(ans, low);
        if (solve(high)) ans = max(ans, high);
        if (ans == -1) puts("Poor RunningPhoton!");
        else printf("%d\n", ans);
    }

    // printf("\nTime cost: %.2fs\n", 1.0 * (clock() - _) / CLOCKS_PER_SEC);
    return 0;
}

I.玛雅,好简单

题意

分析

求无向图桥边的模版题。。。。
/*****************************************
Author      :Crazy_AC(JamesQi)
Time        :2016
File Name   :
                   _ooOoo_
                  o8888888o
                  88" . "88
                  (| -_- |)
                  O\  =  /O
               ____/`---'\____
             .'  \|     |//  `.
            /  \|||  :  |||//  \
           /  _||||| -:- |||||-  \
           |   | \\  -  /// |   |
           | \_|  ''\---/''  |   |
           \  .-\__  `-`  ___/-. /
         ___`. .'  /--.--\  `. . __
      ."" '<  `.___\_<|>_/___.'  >'"".
     | | :  `- \`.;`\ _ /`;.`/ - ` : | |
     \  \ `-.   \_ __\ /__ _/   .-` /  /
======`-.____`-.___\_____/___.-`____.-'======
                   `=---='
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         佛祖保佑       永无BUG
*****************************************/
// #pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <climits>
using namespace std;
#define MEM(x,y) memset(x, y,sizeof x)
#define pk push_back
#define lson rt << 1
#define rson rt << 1 | 1
#define bug cout << "BUG HERE\n"
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> ii;
typedef pair<ii,int> iii;
const double eps = 1e-8;
const double pi = 4 * atan(1);
const int inf = 1 << 30;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
int nCase = 0;
int dcmp(double x){//精度正负、0的判断
    if (fabs(x) < eps) return 0;
    return x < 0?-1:1;
}
inline int read(){
    char c = getchar();
    while (!isdigit(c)) c = getchar();
    int x = 0;
    while (isdigit(c)) {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x;
}
const int maxn = 10010;
vector<int> G[maxn];
int dfn[maxn], low[maxn], depth;
bool in[maxn];
int cnt;
stack<int> st;
void dfs(int u,int fa) {
    dfn[u] = low[u] = ++depth;
    st.push(u);
    in[u] = true;
    int first = 1;
    for (int i = 0;i < G[u].size();++i) {
        int v = G[u][i];
        if (first && v == fa) {
            first = 0;
            continue;
        }
        if (dfn[v] == -1) {
            dfs(v, u);
            if (low[v] > dfn[u]) cnt++;
            low[u] = min(low[u], low[v]);
        }else if (in[v]) low[u] = min(low[u], dfn[v]);
    }
    if (dfn[u] == low[u]) {
        while(true) {
            int x = st.top();
            st.pop();
            in[x] = false;
            if (x == u) break;
        }
    }
}
int n, m;
void solve() {
    memset(dfn, -1,sizeof dfn);
    cnt = depth = 0;
    for (int i  =1;i <= n;++i)
        if (dfn[i] == -1) dfs(i, -1);
    printf("Case %d: %d\n", ++nCase, cnt);
}
int main(int argc, const char * argv[])
{   
    // freopen("in.txt","r",stdin);
    // freopen("out.txt","w",stdout);
    // clock_t _ = clock();

    int t;
    scanf("%d", &t);
    while(t--) {
        scanf("%d%d", &n, &m);
        for (int i = 1;i <= n;++i)
            G[i].clear();
        int u, v;
        for (int i = 1;i <= m;++i) {
            scanf("%d%d", &u, &v);
            G[u].push_back(v);
            G[v].push_back(u);
        }
        solve();
    }

    // printf("\nTime cost: %.2fs\n", 1.0 * (clock() - _) / CLOCKS_PER_SEC);
    return 0;
}

J.An Easy Problem

题意

就是选最少的人进行路径覆盖

分析

先闭包传递,然后二分图匹配最小路径覆盖。
const int N = 1010;
vector<int> G1[N], G2[N], G3[N];//原图,扩张图,缩点后的图。
bool vis[N];
int pre[N], low[N], Belong[N], scc_cnt, Times;
int n, m;
stack<int> st;
void Tarjan(int u) {
    pre[u] = low[u] = ++Times;
    st.push(u);
    for (int i = 0;i < (int)G2[u].size();++i) {
        int v = G2[u][i];
        if (!pre[v]) {
            Tarjan(v);
            low[u] = min(low[u], low[v]);
        }else if (!Belong[v]) low[u] = min(low[u], pre[v]);
    }
    if (pre[u] == low[u]) {
        scc_cnt++;
        while(true) {
            int x = st.top();
            st.pop();
            Belong[x] = scc_cnt;
            if (x == u) break;
        }
    }
}
void FindSCC() {
    memset(pre, 0,sizeof pre);
    memset(Belong, 0,sizeof Belong);
    Times = scc_cnt = 0;
    for (int i = 1;i <= n;++i) {
        if (!pre[i]) Tarjan(i);
    }
}
void BFS(int st) {
    queue<int> que;
    que.push(st);
    memset(vis, false,sizeof vis);
    vis[st] = true;
    while(!que.empty()) {
        int u = que.front();
        que.pop();
        for (int i = 0;i < G1[u].size();++i) {
            int v = G1[u][i];
            if (vis[v]) continue;
            vis[v] = true;
            G2[st].push_back(v);//对原图进行这种扩展是不会形成可行环的。
            que.push(v);
        }
    }
}
void Initation() {
    for (int i = 1;i <= n;++i)
        BFS(i);
}
void Input() {
    scanf("%d%d",&n,&m);
    for (int i = 1;i <= n;++i)
        G1[i].clear(),G2[i].clear(),G3[i].clear();
    int u, v;
    for (int i = 1;i <= m;++i) {
        scanf("%d%d",&u,&v);
        G1[u].push_back(v);
    }
}
void Trans() {
    for (int u = 1;u <= n;++u) {
        for (int i = 0;i < G2[u].size();++i) {
            int v = G2[u][i];
            if (Belong[u] != Belong[v])
                G3[Belong[u]].push_back(Belong[v]);
        }
    }
}
int linker[N];
bool Search(int u) {
    for (int i = 0;i < G3[u].size();++i) {
        int v = G3[u][i];
        if (vis[v]) continue;
        vis[v] = true;
        if (linker[v] == -1 || Search(linker[v])) {
            linker[v] = u;
            return true;
        }
    }
    return false;
}
int Hungary() {
    int ret = 0;
    memset(linker, -1,sizeof linker);
    for (int i = 1;i <= scc_cnt;++i) {
        memset(vis, false,sizeof vis);
        if (Search(i)) ret++;
    }
    return ret;
}
int main()
{   
    // freopen("in.txt","r",stdin);
    // freopen("out.txt","w",stdout);
    int t, icase = 0;
    scanf("%d",&t);
    while(t--) {
        Input();
        Initation();
        FindSCC();
        // printf("SCC = %d\n", scc_cnt);
        // for (int i = 1;i <= n;++i)
            // printf("%d ", Belong[i]);
        // puts("");
        Trans();

        // for (int i = 1;i <= n;++i) {
            // printf("<%d>::", i);
            // for (int j = 0;j < G2[i].size();++j)
                // printf("%d ", G2[i][j]);
            // puts("");
        // }

        // for (int i = 1;i <= scc_cnt;++i) {
        //  printf("i = %d::::", i);
        //  for (int j = 0;j < G3[i].size();++j)
        //      printf("%d ",G3[i][j]);
        //  puts("");
        // }
        printf("Case %d: %d\n", ++icase, scc_cnt - Hungary());
    }
    return 0;
}

K.投票

题意

投票是单向的且具有传递性,求获得票数最多的人。。。

分析

首先一个连通分量里面的人获得的票数肯定是一样的,然后缩点成DAG题,反向建边,再从入读为0的点开始搜索。
/*****************************************
Author      :Crazy_AC(JamesQi)
Time        :2016
File Name   :
                   _ooOoo_
                  o8888888o
                  88" . "88
                  (| -_- |)
                  O\  =  /O
               ____/`---'\____
             .'  \|     |//  `.
            /  \|||  :  |||//  \
           /  _||||| -:- |||||-  \
           |   | \\  -  /// |   |
           | \_|  ''\---/''  |   |
           \  .-\__  `-`  ___/-. /
         ___`. .'  /--.--\  `. . __
      ."" '<  `.___\_<|>_/___.'  >'"".
     | | :  `- \`.;`\ _ /`;.`/ - ` : | |
     \  \ `-.   \_ __\ /__ _/   .-` /  /
======`-.____`-.___\_____/___.-`____.-'======
                   `=---='
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
         佛祖保佑       永无BUG
*****************************************/
// #pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <algorithm>
#include <iomanip>
#include <sstream>
#include <string>
#include <stack>
#include <queue>
#include <deque>
#include <vector>
#include <map>
#include <set>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <climits>
using namespace std;
#define MEM(x,y) memset(x, y,sizeof x)
#define pk push_back
#define lson rt << 1
#define rson rt << 1 | 1
#define bug cout << "BUG HERE\n"
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> ii;
typedef pair<ii,int> iii;
const double eps = 1e-8;
const double pi = 4 * atan(1);
const int inf = 1 << 30;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
int nCase = 0;
int dcmp(double x){//精度正负、0的判断
    if (fabs(x) < eps) return 0;
    return x < 0?-1:1;
}
inline int read(){
    char c = getchar();
    while (!isdigit(c)) c = getchar();
    int x = 0;
    while (isdigit(c)) {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x;
}
const int maxn = 5010;
const int maxm = 30010;
int head[maxn], pnt[maxm], nxt[maxm], ecnt;
int n, m;
int dfn[maxn], low[maxn], in[maxn], depth;
int belong[maxn], block;
int cnt1[maxn],cnt2[maxn], cnt3[maxn];
stack<int> st;
void dfs(int u) {
    dfn[u] = low[u] = ++depth;
    in[u] = 1;
    st.push(u);
    for (int i = head[u]; ~i; i = nxt[i]) {
        int v = pnt[i];
        if (dfn[v] == -1) {
            dfs(v);
            low[u] = min(low[u], low[v]);
        }else if (in[v]) low[u] = min(low[u], dfn[v]);
    }
    if (dfn[u] == low[u]) {
        block++;
        while(true) {
            int x = st.top();
            st.pop();
            in[x] = 0;
            belong[x] = block;
            cnt1[block]++;
            if (x == u) break;
            // cnt1[block]++;
        }
    }
}
void find_scc() {
    memset(dfn, -1,sizeof dfn);
    memset(in, 0,sizeof in);
    memset(cnt1, 0,sizeof cnt1);//scc
    depth = block = 0;
    for (int i = 0;i < n;++i)
        if (dfn[i] == -1) dfs(i);
}
vector<int> G[maxn];
int mark[maxn];
int search(int u) {
    int sum = 0;
    for (int i = 0;i < G[u].size();++i) {
        int v = G[u][i];
        if (mark[v]) continue;
        mark[v] = 1;
        sum += cnt1[v];
        sum += search(v);
    }
    return sum;
}
void solve() {
    for (int i = 1;i <= block;++i)
        G[i].clear();
//rebuild new graph
    for (int u = 0;u < n;++u) {
        for (int i = head[u]; ~i;i = nxt[i]) {
            int v = pnt[i];
            if (belong[u] != belong[v]) {
                G[belong[v]].push_back(belong[u]);
                in[belong[u]]++;
            }
        }
    }
    memset(cnt2, 0,sizeof cnt2);
    for (int i = 1;i <= block;++i) {
        if (in[i] == 0) {
            memset(mark, 0,sizeof mark);
            cnt2[i] = search(i);
        }
    }
    int Max = 0;
    for (int i = 0;i < n;++i) {
        cnt3[i] = cnt1[belong[i]] + cnt2[belong[i]] - 1;
        // cout << "cnt3 = " << cnt3[i] << endl;
        Max = max(Max, cnt3[i]);
    }
    printf("Case %d: %d\n", ++nCase, Max);
    int first = 1;
    for (int i = 0;i < n;++i) {
        if (cnt3[i] == Max) {
            if (first) first = 0;
            else printf(" ");
            printf("%d", i);
        }
    }
    printf("\n");
}
int main(int argc, const char * argv[])
{    
    // freopen("in.txt","r",stdin);
    // freopen("out.txt","w",stdout);
    // clock_t _ = clock();

    int t;
    cin >> t;
    while(t--) {
        scanf("%d %d", &n, &m);
        memset(head, -1,sizeof head), ecnt = 0;
        int u, v;
        for (int i = 1;i <= m;++i) {
            scanf("%d %d", &u, &v);
            pnt[ecnt] = v, nxt[ecnt] = head[u], head[u] = ecnt++;
        }
        find_scc();
        solve();
    }

    // printf("\nTime cost: %.2fs\n", 1.0 * (clock() - _) / CLOCKS_PER_SEC);
    return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

HDU 6038 (2017 多校训练赛1 1006) Function(图论)

2017 Multi-University Training Contest - Team 1 1006 Function Time Limit: 4000/2000 MS (Java/Other...

UVALive 3211 (训练指南)图论例题9 2-sat+二分

/** 2-sat模板 **/ #include #include #include #include #include #include using namespace std; con...

图论进阶训练

残暴的逊哥又来血腥镇压我们了,然后给我们布置了很多图论题 有不少也是我没做过的,而且还学了不少新东西,撸完要好好记录一发

HDU 3488 2010多校联合6 图论

Tour Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others) Total Sub...

HDU 3478 2010多校联合5 图论

Catch Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Su...

hdu 5378 Leader in Tree Land 2015多校联合训练赛 树形dp

Leader in Tree Land Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Othe...

变电运行技能训练场

  • 2008-06-14 22:59
  • 1.19MB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:深度学习:神经网络中的前向传播和反向传播算法推导
举报原因:
原因补充:

(最多只允许输入30个字)