洛谷 P2805 [NOI2009]植物大戰殭屍 網絡流 - 最大權閉合子圖

                                  洛谷  P2805 [NOI2009]植物大戰殭屍

題目鏈接

最大權閉合子圖講解

題解 :

將被保護的向保護的的點連邊建圖,然後跑最大閉合子圖,

注意的點, 1.每一行後面的點會保護前面的點  2.會存在環,需要先在反圖跑一個拓撲圖去環和環上直接或間接保護的點。

 

#include <bits/stdc++.h>

using namespace std;

const int maxn = 1000;
const int maxm = 3e6+10;
const int INF = 0x3f3f3f3f;
int n,m,tot;
int l[maxn],h[maxn],cur[maxn];

struct edge
{
    int to, c, next;
    edge(int to = 0, int c = 0, int next = 0) : to(to) ,c(c), next(next) {}
}es[maxm];

void add_edge(int u , int v, int c)
{
    es[tot] = edge(v,c,h[u]);  h[u] = tot++;
    es[tot] = edge(u,0,h[v]);  h[v] = tot++;
    //cout << u << " " << v << " " << c << endl;
}

bool bfs(int s, int t)
{
    memset(l,0,sizeof(l));
    l[s] = 1;
    queue <int> Q;
    Q.push(s);
    while(!Q.empty())
    {
        int u = Q.front();Q.pop();
        if(u == t) return true;
        for(int i = h[u]; ~i; i = es[i].next)
        {
            int v = es[i].to;
            if(es[i].c && !l[v]) {l[v] = l[u] + 1; Q.push(v);}
        }
    }
    return false;
}


int dfs(int x, int t, int mf)
{
    if(x == t) return mf;
    int ret = 0;
    for(int &i = cur[x]; ~i; i = es[i].next)
    {
        int v = es[i].to;
        if(es[i].c && l[v] == l[x] + 1)
        {
            int f = dfs(v,t,min(es[i].c, mf-ret));
            es[i].c -= f;
            es[i^1].c += f;
            ret += f;
            if(ret == mf) return ret;
        }
    }
    return ret;
}

int dinic(int s,int t)
{
    int res = 0;
    while(bfs(s,t))
    {
        for(int i = 0; i <= t; i++) cur[i] = h[i];
          res += dfs(s,t,INF);
    }
    return res;
}


int sum=0;

int sc[maxn];
int vis[maxn];
int d[maxn];
vector <int> G[maxn];


void tuopu()
{
   queue<int> q;
   for(int i = 1; i <= n; i++)
     if(d[i] == 0) q.push(i);

   while(!q.empty())
   {
       int u = q.front(); q.pop(); vis[u] = true;
       for(int i = 0; i < G[u].size(); i++)
       {
           int v = G[u][i];
           d[v]--;
           if(!d[v]) q.push(v);
       }
   }
}


int main()
{
    tot = 0;
    memset(d,0,sizeof(d));
    memset(h,-1,sizeof(h));
    memset(vis,false,sizeof(vis));
    int r,c;
    scanf("%d%d",&r,&c);
    int s = 0, t = r*c+1;
    n = r*c;
    for(int i = c; i > 1; i--)
        for(int j = 1; j <= r; j++)
           {
               int u = (j-1)*c + i, v= (j-1)*c + i-1;
               G[u].push_back(v);
               d[v]++;
           }

    for(int i = 1; i <= r*c; i++)
    {
        int w;
        scanf("%d%d",&sc[i],&w);
        for(int j = 1; j <= w; j++)
        {
            int ri,ci;
            scanf("%d%d",&ri,&ci);
            G[i].push_back(ri*c+ci+1);
            d[ri*c+ci+1] ++;
        }
    }

    tuopu();

    //for(int i = 1; i <= n; i++)
      //      if(vis[i]) cout << i << "**";
    //cout <<"*"<<endl;
    for(int i = 1; i <= n; i++)
       if(vis[i])
       {
       if(sc[i] < 0) add_edge(i,t,-sc[i]);
       else add_edge(s,i,sc[i]),sum += sc[i];
       for(int j = 0; j < G[i].size(); j++)
           if(vis[G[i][j]])  add_edge(G[i][j],i,INF);
       }

  //  cout << sum << endl;
    int ans = sum - dinic(s,t);
    printf("%d\n",ans);
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章