A new season of Touhou M-1 Grand Prix is approaching. Girls in Gensokyo cannot wait for participating it. Before the registration, they have to decide which combination they are going to compete as. Every girl in Gensokyo is both a boke (funny girl) and a tsukkomi (straight girl). Every candidate combination is made up of two girls, a boke and a tsukkomi. A girl may belong to zero or more candidate combinations, but one can only register as a member of one formal combination. The host of Touhou M-1 Grand Prix hopes that as many formal combinations as possible can participate in this year. Under these constraints, some candidate combinations are actually redundant as it\'s impossible to register it as a formal one as long as the number of formal combinations has to be maximized. So they want to figure out these redundant combinations and stop considering about them.
Input
There are multiple test cases. Process to the End of File.
The first line of each test case contains two integers: 1 ≤ N ≤ 40 and 1 ≤ M ≤ 123, where N is the number of girls in Gensokyo, and M is the number of candidate combinations. The following M lines are M candidate combinations, one by each line. Each combination is represented by two integers, the index of the boke girl 1 ≤ B i ≤ N and the index of the tsukkomi girl 1 ≤ T i ≤ N, where B i != T i.
The first line of each test case contains two integers: 1 ≤ N ≤ 40 and 1 ≤ M ≤ 123, where N is the number of girls in Gensokyo, and M is the number of candidate combinations. The following M lines are M candidate combinations, one by each line. Each combination is represented by two integers, the index of the boke girl 1 ≤ B i ≤ N and the index of the tsukkomi girl 1 ≤ T i ≤ N, where B i != T i.
Output
For each test case, output the number of redundant combinations in the first line. Then output the space-separated indexes of the redundant combinations in ascending order in the second line.
思路:一般图的匹配问题,要求输出失配组合的下标
问题就是找出失配的组合。记原来的答案为 t . 我们依次删去一个组合,如果删去次组合后, 再求依次匹配数 记为 t',如果 t != t'那么,这个删去的组合为失配的,需要输出
/***********************************************
* Author: fisty
* Created Time: 2015-08-26 14:18:02
* File Name : B.cpp
*********************************************** */
#include <iostream>
#include <cstring>
#include <deque>
#include <cmath>
#include <queue>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <string>
#include <vector>
#include <cstdio>
#include <bitset>
#include <algorithm>
using namespace std;
#define Debug(x) cout << #x << " " << x <<endl
#define Memset(x, a) memset(x, a, sizeof(x))
const int INF = 0x3f3f3f3f;
typedef long long LL;
typedef pair<int, int> P;
#define FOR(i, a, b) for(int i = a;i < b; i++)
#define lson l, m, k<<1
#define rson m+1, r, k<<1|1
#define MAX_N 200
const int MAXN = 450;
int N, M; //点的个数,点的编号从1到N
bool Graph[MAXN][MAXN];
int Match[MAXN];
bool InQueue[MAXN],InPath[MAXN],InBlossom[MAXN];
int Head,Tail;
int Queue[MAXN];
int Start,Finish;
int NewBase;
int Father[MAXN],Base[MAXN];
int Count;//匹配数,匹配对数是Count/2
int p_tot, q_tot;
struct Point{
int x, y;
}p[MAX_N], q[MAX_N];
void Push(int u)
{
Queue[Tail] = u;
Tail++;
InQueue[u] = true;
}
int Pop()
{
int res = Queue[Head];
Head++;
return res;
}
int FindCommonAncestor(int u,int v)
{
memset(InPath,false,sizeof(InPath));
while(true)
{
u = Base[u];
InPath[u] = true;
if(u == Start) break;
u = Father[Match[u]];
}
while(true)
{
v = Base[v];
if(InPath[v])break;
v = Father[Match[v]];
}
return v;
}
void ResetTrace(int u)
{
int v;
while(Base[u] != NewBase)
{
v = Match[u];
InBlossom[Base[u]] = InBlossom[Base[v]] = true;
u = Father[v];
if(Base[u] != NewBase) Father[u] = v;
}
}
void BloosomContract(int u,int v)
{
NewBase = FindCommonAncestor(u,v);
memset(InBlossom,false,sizeof(InBlossom));
ResetTrace(u);
ResetTrace(v);
if(Base[u] != NewBase) Father[u] = v;
if(Base[v] != NewBase) Father[v] = u;
for(int tu = 1; tu <= N; tu++)
if(InBlossom[Base[tu]])
{
Base[tu] = NewBase;
if(!InQueue[tu]) Push(tu);
}
}
void FindAugmentingPath()
{
memset(InQueue,false,sizeof(InQueue));
memset(Father,0,sizeof(Father));
for(int i = 1;i <= N;i++)
Base[i] = i;
Head = Tail = 1;
Push(Start);
Finish = 0;
while(Head < Tail)
{
int u = Pop();
for(int v = 1; v <= N; v++)
if(Graph[u][v] && (Base[u] != Base[v]) && (Match[u] != v))
{
if((v == Start) || ((Match[v] > 0) && Father[Match[v]] > 0))
BloosomContract(u,v);
else if(Father[v] == 0)
{
Father[v] = u;
if(Match[v] > 0)
Push(Match[v]);
else
{
Finish = v;
return;
}
}
}
}
}
void AugmentPath()
{
int u,v,w;
u = Finish;
while(u > 0)
{
v = Father[u];
w = Match[v];
Match[v] = u;
Match[u] = v;
u = w;
}
}
int Edmonds()
{
memset(Match,0,sizeof(Match));
for(int u = 1; u <= N; u++)
if(Match[u] == 0)
{
Start = u;
FindAugmentingPath();
if(Finish > 0)AugmentPath();
}
Count = 0;
for(int u = 1; u <= N;u++)
if(Match[u] > 0)
Count++;
return Count/2;
}
void PrintMatch()
{
//printf("%d\n",Count);
/*for(int u = 1; u <= N; u++)
if(u < Match[u]){
q[q_tot].x = u;
q[q_tot++].y = Match[u];
}
*/
int _ans = Edmonds();
// Debug(_ans);
vector<int> ans;
ans.clear();
for(int i = 1;i <= M; i++){
Memset(Graph, false);
for(int j = 1;j <= M; j++){
if(i != j){
if(p[i].x == p[j].y || p[i].y == p[j].x || p[i].x == p[j].x || p[i].y == p[j].y){
continue;
}
int a = p[j].x;
int b = p[j].y;
Graph[a][b] = Graph[b][a] = true;
}
}
int ts = Edmonds();
if(ts != _ans - 1){
ans.push_back(i);
}
}
int t = ans.size();
//Debug(t);
printf("%d\n", t);
sort(ans.begin(), ans.end());
if(t)
printf("%d", ans[0]);
for(int i = 1;i < t; i++){
printf(" %d", ans[i]);
}
printf("\n");
}
int main()
{
int u,v;
while(scanf("%d%d",&N,&M) != EOF){
memset(Graph,false,sizeof(Graph));
for(int i = 1;i <= M; i++){
scanf("%d%d",&u,&v);
Graph[u][v] = Graph[v][u] = true;
p[i].x = u;
p[i].y = v;
}
PrintMatch();//输出匹配数和匹配
}
return 0;
}