您的位置:首页 > 其它

2013 ACM/ICPC Asia Regional Changsha Online - I Grand Prix

2013-09-23 00:14 447 查看
离正解非常非常接近就差一步的感觉真让人忧伤_(:3」∠)_

第一步肯定是求出最大匹配,数据范围挺大,连Dinic都超时,只能使用Hopcroft-Karp算法来求。

求出最大匹配ans后,先是一个朴素的想法。

枚举每条不是匹配的边(u,v),把它强行匹配,就是删去u,v两点,看新图的最大匹配数是否是ans-1,是的话它就可能出现在最大匹配中。

但这样的时间复杂度明显过大。

删去了u和v两点至多删去两个匹配,如果新图的匹配是ans-1就意味着u,v两点原来匹配的两点可以找到一条增广路径。

先假设用的就是dinic算法求的匹配,那么很明显的是(u,v)是最大匹配等价于有条从v到u的路,反之则有条从u到v的路。

所以每次询问u到v是否有路时,一定存在边(v,u),故问题等价于判断u与vv是否可以相互到达。

综上只需要把Hopcroft-Karp求出匹配的结果还原到网络流上,并在这个图上求出强连通分量,对于每条非匹配边,判断u和v不在一个SCC里面,

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cstdlib>
#include <cmath>
#include <cctype>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <list>
#define pb push_back
#define mp make_pair
#define fi first
#define se second
//#pragma comment(linker, "/STACK:16777216")
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
#define N 40005
#define M 1000005

int n , m , p , s , t , ans;
pair<int , int> ee[200000];
struct arc
{
  int x , next;
}e[M] , g[M];
int pre
 , mcnt , tmp
 , ncnt;

void addarc(int x ,int y)
{
  e[mcnt] = (arc) {y , pre[x]} , pre[x] = mcnt ++;
}
void addedge(int x ,int y)
{
  g[ncnt] = (arc) {y , tmp[x]} , tmp[x] = ncnt ++;
}

int mx
 , my
;
queue<int> que;
int dx
 , dy
;
bool vis
;

bool find(int x)
{
    for (int i = pre[x] ; ~i ; i = e[i].next)
    {
        int y = e[i].x;
        if (!vis[y] && dy[y] == dx[x] + 1)
        {
            vis[y] = 1;
            if (!~my[y] || find(my[y]))
            {
                mx[x] = y , my[y] = x;
                return 1;
            }
        }
    }
    return 0;
}

int matching()
{
    memset(mx , -1 , sizeof(mx));
    memset(my , -1 , sizeof(my));
    int ans = 0;
    while (1){
        bool flag = 0;
        while (!que.empty()) que.pop();
        memset(dx , 0 , sizeof(dx));
        memset(dy , 0 , sizeof(dy));
        for (int i = 0 ; i < n ; ++ i)
            if (!~mx[i]) que.push(i);
        while (!que.empty())
        {
            int x = que.front(); que.pop();
            for (int i = pre[x] ; ~i ; i = e[i].next)
            {
                int y = e[i].x;
                if (!dy[y])
                {
                    dy[y] = dx[x] + 1 ;
                    if (~my[y])
                        que.push(my[y]) , dx[my[y]] = dy[y] + 1;
                    else
                        flag = 1;
                }
            }
        }
        if (!flag) break;
        memset(vis , 0 , sizeof(vis));
        for (int i = 0 ; i < n ; ++ i)
            if (!~mx[i] && find(i)) ++ ans;
    }
    return ans;
}

int idx , scnt , low
 , DFN
 , bel
;
stack<int> st; bool is
;
void tarjan(int x)
{
  int i , y;
  DFN[x] = low[x] = ++ idx;
  is[x] = 1 , st.push(x);
  for (i = tmp[x] ; ~i ; i = g[i].next)
  {
    y = g[i].x;
    if (!DFN[y])
    {
      tarjan(y);
      low[x] = min(low[x] , low[y]);
    }
    else if (is[y])
      low[x] = min(low[x] , DFN[y]);
  }
  if (DFN[x] == low[x])
  {
    scnt ++;
    do
    {
      i = st.top() , st.pop();
      is[i] = 0 , bel[i] = scnt;
    }while (x != i);
  }
}

char str[10];
vector<int> res;
void work()
{
  int i , j , x , y;
  scanf("%d%d",&m,&p);
  memset(pre , -1 , sizeof(pre)) , mcnt = 0;
  s = n + m , t = s + 1;
  for (i = 0 ; i < p ; ++ i)
  {
    scanf("%s" , str);
    x = y = 0;
    for (j = 0 ; j < 3 ; ++ j)
    {
      x <<= 5;
      if (isdigit(str[j]))
        x |= (str[j] - '0');
      else  x |= (str[j] - 'A' + 10);
    }
    for (j = 3 ; j < 6 ; ++ j)
    {
      y <<= 5;
      if (isdigit(str[j]))
        y |= (str[j] - '0');
      else  y |= (str[j] - 'A' + 10);
    }
    ee[i] = make_pair(x , y);
    addarc(x , n + y);
  }

  res.clear();
  ans = matching();

  memset(tmp , -1 , sizeof(tmp)) , ncnt = 0;
  for (i = 0 ; i < n ; ++ i)
    if (!~mx[i])
       addedge(s , i);
    else addedge(i , s);
  for (i = n ; i < n + m ; ++ i)
    if (!~my[i])
       addedge(i , t);
    else addedge(t , i);
  for (x = 0 ; x < n ; ++ x)
    for (i = pre[x] ; ~i ; i = e[i].next)
      if (mx[x] != e[i].x)
        addedge(x , e[i].x);
      else addedge(e[i].x , x);

  scnt = idx = 0;
  memset(low , 0 , sizeof(low));
  memset(DFN , 0 , sizeof(DFN));
  for (i = 0 ; i <= t ; ++ i)
    if (!DFN[i])
      tarjan(i);

  for (i = 0 ; i < p ; ++ i)
  {
    x = ee[i].fi , y = ee[i].se;
    if (mx[x] == y + n) continue;
    if (bel[x] != bel[y + n])
        res.push_back(i);
  }

  printf("%d\n" ,res.size());
  for (i = 0 ; i < res.size() ; ++ i)
  {
    if (i) printf(" ");
    printf("%d" , res[i]);
  }
  printf("\n");
}

int main()
{
    //freopen("~input.txt" , "r" , stdin);
    //int _; scanf("%d\n",&_); while (_--)
    while (~scanf("%d",&n))
        work();
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: