CSP-S improve bovine off before training camp group desert dot column 2 T2

Original title link

Algorithm is not difficult, and when the game is on the cyc Gangster yy positive solution together, but because of time post more anxious (to get back to the bedroom mess), I have two arrays directly to burst open the wrong size 50, cyc Gangster only the documents enter off the half, the direct blast zero (╯¯Д¯) ╯┻━┻

To try to make \ (k \) times the border erase can contribute, then it is easy to think of cutting edge.
So we will start with \ (\ mathtt {tarjan} \ ) ran all the cutting edge, and each can produce a cutting edge \ (1 \) contributions, so there \ (sum_ {bridge} \) strip cutting edge, it You can increase \ (sum_ {bridge} \) interconnecting blocks.
If \ (K \ leqslant Bridge sum_ {} \) , then the final answer is \ (K + S \) (FIG original provided with a \ (S \) interconnecting block).
If \ (K> Bridge sum_ {} \) , then deleting the first cutting edge, the remaining \ (k '= k - sum_ {bridge} \) number of puncturing strip edges.
Then we consider how to get the rest of the map of the border erase the largest contribution.
Found easily by deleting the cutting edge is a simple single ring or multiple rings in a simple set of connected points in FIG.
A plurality of simple rings attached at the point, in fact, we can put a plurality of connections into a plurality of split ring monocyclic, as shown below:

Since a plurality of rings, although apart to be more than a few points, but at the same time increased by the same number of blocks in communication, so the plurality monocyclic disassembled after erase borders greatest contribution is the same as the original.
Then we consider how to delete the collection in this single ring side makes the maximum contribution, apparently for a ring, not always a contribution to be deleted so that it becomes a side chain, after every Erase can produce \ ( 1 \) contribution.
So we need to minimize the number of contribution without first deleting the edges, so greedy strategy is obvious, and soon all the ring by the ring size (ie the number of edges) in descending order, and then try to delete one by side until the number of Border Erase \ ( k '\) light or light until the edge is deleted.
For a single ring puncturing contribution edge generated when the \ (K '> size_ {Circle} \) (the size of the set ring is \ (size_ {Circle} \) ), the contribution to the \ (size_ {circle} - 1 \) ; if \ (K '<= size_ Circle} {\) , the contribution to the \ (K' -. 1 \) .

As to how to find a plurality of rings (have identified and marked cutting edge), we can use \ (\ mathtt DFS} {\) , in a way to find timestamping, can view the code portions embodied.

If using bucket sorting rows, then the time complexity is \ (O (n-m +) \) , people like me lazy directly \ (\ mathtt {sort} \ ) will be more of a \ (\ log \) .

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1e6 + 10;
const int M = 2e6 + 10;
int fi[N], di[M << 1], ne[M << 1], bridge[M << 1], dfn[N], low[N], circle[N], cir_s, l = 1, ti, bridge_sum;
//fi,di,ne为邻接表,bridge储存某一边是否是割边,dfn为时间戳,low为tarjan中的追溯值,circle储存每个单环的大小。
bool fa_l[M << 1];//dfs中用来判断边是否已经走过
inline int re()//快读
{
    int x = 0;
    char c = getchar();
    bool p = 0;
    for (; c < '0' || c > '9'; c = getchar())
        p |= c = '-';
    for (; c >= '0' && c <= '9'; c = getchar())
        x = x * 10 + c - '0';
    return p ? -x : x;
}
inline void add(int x, int y) { di[++l] = y; ne[l] = fi[x]; fi[x] = l; }//加边
inline int minn(int x, int y) { return x < y ? x : y; }
bool comp(int x, int y) { return x > y; }
void tarjan(int x, int la)//tarjan找割边模板
{
    int i, y;
    dfn[x] = low[x] = ++ti;
    for (i = fi[x]; i; i = ne[i])
        if (!dfn[y = di[i]])
        {
            tarjan(y, i);
            low[x] = minn(low[x], low[y]);
            if (low[y] > dfn[x])
                bridge[i] = bridge[i ^ 1] = 1, bridge_sum++;
        }
        else
            if (i ^ la ^ 1)
                low[x] = minn(low[x], dfn[y]);
}
void dfs(int x)//找出各个环
{
    int i, y;
    for (i = fi[x]; i; i = ne[i])
        if (!bridge[i] && !fa_l[i])//如果这条边不是割边且没有走过
            if (!dfn[y = di[i]])//如果边所连的点没有走过
                dfn[y] = dfn[x] + 1, fa_l[i] = fa_l[i ^ 1] = 1, dfs(y);//标记时间戳;记录这条边已走过;继续搜索
            else//如果走过了
                fa_l[i] = fa_l[i ^ 1] = 1, circle[++cir_s] = dfn[x] + 1 - dfn[y];//同样要记录这条边已走过,否则在回溯的时候会出锅;将该环的大小计入数组
}
int main()
{
    int i, n, m, k, x, y, ans = 0;
    n = re(); m = re(); k = re();
    for (i = 1; i <= m; i++)//输入图
    {
        x = re(); y = re();
        add(x, y); add(y, x);
    }
    for (i = 1; i <= n; i++)//tarjan找割边,同时统计原图连通块的个数
        if (!dfn[i])
            tarjan(i, 0), ans++;
    if (k <= bridge_sum)//若k不够删去所有割边,就直接输出答案
        return printf("%d", k + ans), 0;
    ans += bridge_sum; k -= bridge_sum;//统计答案并将k减去割边数
    memset(dfn, 0, sizeof(dfn));
    for (i = 1; i <= n; i++)//找环
        if (!dfn[i])
            dfn[i] = 1, dfs(i);
    sort(circle + 1, circle + cir_s + 1, comp);
    for (i = 1; i <= cir_s; i++)//贪心删边并统计贡献
        if (k >= circle[i])
            ans += circle[i] - 1, k -= circle[i];
        else
        {
            ans += k - 1;
            break;
        }
    return printf("%d", ans), 0;
}

Guess you like

Origin www.cnblogs.com/Iowa-Battleship/p/11779063.html