TOJ 3345 Chinese Chess 二分匹配 匈牙利算法 扩展
TOJ
3345
Chinese Chess http://acm.tju.edu.cn/toj/showp3345.html
双链表实习双向邻接表,正向图反向图,匈牙利匹配后,枚举删除匹配边,两边做重新查找增广路操作,如果都没法查到则证明是重要边,还原原匹配时候要注意细节。
双链表实习双向邻接表,正向图反向图,匈牙利匹配后,枚举删除匹配边,两边做重新查找增广路操作,如果都没法查到则证明是重要边,还原原匹配时候要注意细节。
优化1:求最大匹配时候先能匹配就匹配上。
优化2:标记已经确定不是必要点的行和列 flag[]和flag2[]
注意1:删除匹配边后 应在匹配边的两面点 分别查询
注意2:没查到新匹配要还原匹配边
#include < stdio.h >
#include < string .h >
const int size2 = 100110 ;
const int size1 = 10110 ;
int n , m , k ;
struct node{
node * p;
node * q;
int v;
int v2;
};
int val;
node edg[size2];
bool visit[size1];
int pp[size1];
bool flag[size1];
bool flag2[size1];
node * g[size1];
node * g1[size1];
int ppre[size1];
int ppr[size1];
int nxy[size1];
inline bool check( int x , int y , int fc){
node * now = g[x];
while (now != NULL){
if (now -> v == y){
if (fc == 0 )
return true ;
if (fc == 1 ){
now -> v = - 1 ;
return true ;
}
if (fc == 2 ){
now -> v = val;
return true ;
}
}
else {
now = now -> p;
}
}
return false ;
}
inline bool check2( int x , int y , int fc){
node * now = g1[x];
while (now != NULL){
if (now -> v2 == y){
if (fc == 0 )
return true ;
if (fc == 1 ){
now -> v2 = - 1 ;
return true ;
}
if (fc == 2 ){
now -> v2 = val;
return true ;
}
}
else {
now = now -> q;
}
}
return false ;
}
inline bool find( int a){
node * now = g[a];
while (now != NULL){
int i = now -> v;
if (i != - 1 ){
if ( ! visit[i] ){
visit[i] = true ;
if (pp[i] == - 1 || find(pp[i])){
pp[i] = a;
nxy[a] = i;
return true ;
}
}
}
now = now -> p;
}
return false ;
}
inline bool find2( int a){
node * now = g1[a];
while (now != NULL){
int i = now -> v2;
if (i != - 1 ){
if ( ! visit[i] ){
visit[i] = true ;
if (nxy[i] == - 1 || find2(nxy[i])){
nxy[i] = a;
pp[a] = i;
return true ;
}
}
}
now = now -> q;
}
return false ;
}
void output(){
printf( " \n\n " );
for ( int i = 1 ; i <= m ; i ++ )
printf( " %d -> %d\n " ,pp[i],i);
printf( " \n " );
for ( int i = 1 ; i <= n ; i ++ )
printf( " %d -> %d\n " ,i,nxy[i]);
printf( " \n\n " );
}
void output1( int x){
node * now = g1[x];
while (now != NULL){
int i = now -> v2;
printf( " %d " ,i);
now = now -> q;
}
printf( " \n " );
}
int main(){
int a1,i,a2;
int _case = 0 ;
int num;
while (scanf( " %d%d%d " , & n, & m, & k) != EOF){
num = 0 ;
memset(g, 0 , sizeof (g));
memset(g1, 0 , sizeof (g1));
memset(pp, - 1 , sizeof (pp));
memset(nxy, - 1 , sizeof (nxy));
for (i = 1 ; i <= k ; i ++ ){
scanf( " %d%d " , & a1, & a2);
if (check(a1,a2, 0 )) continue ;
edg[i].v = a2;
edg[i].v2 = a1;
edg[i].p = NULL;
edg[i].q = NULL;
if (g[a1] == NULL){
g[a1] = & edg[i];
} else {
edg[ppre[a1]].p = & edg[i];
}
if (g1[a2] == NULL){
g1[a2] = & edg[i];
} else {
edg[ppr[a2]].q = & edg[i];
}
ppre[a1] = i ;
ppr[a2] = i ;
if (pp[a2] == - 1 && nxy[a1] == - 1 ){
pp[a2] = a1;
nxy[a1] = a2;
num ++ ;
}
}
for (i = 1 ; i <= m ; i ++ ){
if (pp[i] == - 1 ){
memset(visit, 0 , sizeof (visit));
if (find2(i)){
num ++ ;
}
}
}
memset(flag, 0 , sizeof (flag));
memset(flag2, 0 , sizeof (flag2));
int ans = 0 ;
for (i = 1 ; i <= m ; i ++ ){
if (pp[i] != - 1 ){
int key = 0 ;
int now = pp[i];
pp[i] = - 1 ;
nxy[now] = - 1 ;
if (flag[pp[i]] == 0 ){
check(now,i, 1 );
memset(visit, 0 , sizeof (visit));
if (find(now)){
key = 1 ;
}
val = i ;
check(now, - 1 , 2 );
}
if (flag2[i] == 0 && key == 0 ){
check2(i,now, 1 );
memset(visit, 0 , sizeof (visit));
if (find2(i)){
key = 1 ;
}
val = now ;
check2(i, - 1 , 2 );
}
if ( ! key){
ans ++ ;
nxy[now] = i;
pp[i] = now;
}
else {
flag[now] = 1 ;
flag2[i] = 1 ;
}
} // 右侧有边
}
printf( " Board %d have %d important blanks for %d chessmen.\n " , ++ _case,ans,num);
}
return 0 ;
}