离正解非常非常接近就差一步的感觉真让人忧伤_(: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[N] , mcnt , tmp[N] , 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[N] , my[N];
queue<int> que;
int dx[N] , dy[N];
bool vis[N];
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[N] , DFN[N] , bel[N];
stack<int> st; bool is[N];
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;
}