棋盘游戏 HDU - 1281
考察:二分图匹配+图论的基本操作
图论题目做多了看到这句不在这些格子上放车,也可以保证尽量多的“车”被放下,应该能反应过来是删边操作
其实我没反应过来
这道题和之前的HDU 1045一样也是缩点操作,通过这道题也搞明白了点之前的缩点操作,行集和列集有交集才能连边,然后就是走一波最大匹配,最后开始一条条删边,(这个边是缩点后的边,即在交集状态下的边,所以不能放在第一个for循环里)
但其实这道题根本不用缩点,给的行列就可以当作缩点后坐标
注意:
- match每次删边后初始化
1 #include <iostream> 2 #include <cstring> 3 #include <algorithm> 4 #include <map> 5 using namespace std; 6 typedef pair<int,int> pii; 7 const int N = 110; 8 pii p[N*N]; 9 int n,m,k,rmp[N][N],cmp[N][N],match[N*N],kcase,kcnt; 10 bool g[N][N],st[N*N]; 11 map<int,int> rm,cm; 12 void inits() 13 { 14 rm.clear(); cm.clear(); kcnt = 0; 15 memset(rmp,0,sizeof rmp); memset(cmp,0,sizeof cmp); 16 memset(g,0,sizeof g); memset(match,-1,sizeof match); 17 } 18 int Getrid(int x) 19 { 20 if(!rm.count(x)) rm[x] = rm.size(); 21 return rm[x]; 22 } 23 int Getcid(int x) 24 { 25 if(!cm.count(x)) cm[x] = cm.size(); 26 return cm[x]; 27 } 28 bool findw(int x) 29 { 30 for(int i=1;i<=cm.size();i++) 31 { 32 if(!g[x][i]||st[i]) continue; 33 st[i] = 1; 34 if(match[i]==-1||findw(match[i])) 35 { 36 match[i] = x; 37 return true; 38 } 39 } 40 return false; 41 } 42 int main() 43 { 44 while(scanf("%d%d%d",&n,&m,&k)!=EOF) 45 { 46 inits(); 47 int res = 0,ans = 0; 48 for(int i=1;i<=k;i++) 49 { 50 int x,y; scanf("%d%d",&x,&y); 51 int row = Getrid(x),col = Getcid(y); 52 rmp[x][y] = row,cmp[x][y] = col; 53 } 54 for(int i=1;i<=n;i++) 55 for(int j=1;j<=n;j++) 56 if(rmp[i][j]) { g[rmp[i][j]][cmp[i][j]] = 1; p[++kcnt].first = rmp[i][j],p[kcnt].second = cmp[i][j];} 57 for(int i=1;i<=rm.size();i++) 58 { 59 memset(st,0,sizeof st); 60 if(findw(i)) res++; 61 } 62 for(int j=1;j<=k;j++) 63 { 64 int x = p[j].first,y = p[j].second,tmp = 0; 65 g[x][y] = 0; 66 memset(match,-1,sizeof match); 67 for(int i=1;i<=rm.size();i++) 68 { 69 memset(st,0,sizeof st); 70 if(findw(i)) tmp++; 71 } 72 if(tmp<res) ans++; 73 g[x][y] = 1; 74 } 75 printf("Board %d have %d important blanks for %d chessmen.\n",++kcase,ans,res); 76 } 77 return 0; 78 }