hdu 4185 Oil Skimming 二分图匹配

Oil Skimming

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/** Aug 24, 2015 11:15:57 AM
* PrjName:hdu4185
* @author Semprathlon
*/
import java.io.*;
import java.util.*;
public class Main {

/**
* @param args
*/
static char[][] mp;
//static int[][] adj;
static int[] match;
static boolean[] vis;
static int n,cnt,sum;
final static int[][] dir={ {-1,0},{1,0},{0,-1},{0,1}};
final static int maxn=605;
static Vector<Integer>[] adj=new Vector[maxn*maxn>>1];
static HashMap<Integer, Integer> sta=new HashMap<Integer,Integer>();
static HashMap<Integer, Integer> stb=new HashMap<Integer,Integer>();
static int geta(Pt p){
int hash=p.hashCode();
if (sta.containsKey(hash))
return sta.get(hash);
else{
sta.put(hash, ++cnt);
return cnt;
}
}
static int getb(Pt p){
int hash=p.hashCode();
if (stb.containsKey(hash))
return stb.get(hash);
else{
stb.put(hash, ++sum);
return sum;
}
}
static boolean cango(int x,int y){
if (x<0||x>=n||y<0||y>=n||mp[x][y]!='#') return false;
return true;
}
static boolean dfs(int u){
for(int v:adj[u]){
if (vis[v]) continue;
vis[v]=true;
if (match[v]<0||dfs(match[v])){
match[v]=u;
return true;
}
}
return false;
}
static int maxmatch(){
int res=0;
Arrays.fill(match, -1);
for(int i=1;i<=cnt;i++){
Arrays.fill(vis, false);
if (dfs(i)) res++;
}
return res;
}
public static void main(String[] args) throws IOException{
// TODO Auto-generated method stub
InputReader in=new InputReader(System.in);
PrintWriter out=new PrintWriter(System.out);
for(int i=0;i<maxn*maxn>>1;i++) adj[i]=new Vector<Integer>();
int T=in.nextInt(),cas=0;

while(T-->0){
n=in.nextInt();
mp=new char[n][n];
for(int i=0;i<n*n>>1;i++) adj[i].clear();
sta.clear();stb.clear();cnt=sum=0;
for(int i=0;i<n;i++){
String s=in.next();
for(int j=0;j<n;j++)
mp[i][j]=s.charAt(j);
}
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if (mp[i][j]=='#'){
Pt p=new Pt(i, j,n);
for(int k=0;k<4;k++){
int x=i+dir[k][0];
int y=j+dir[k][1];
if (((x+y)&1)>0&&cango(x,y)){
Pt q=new Pt(x, y,n);
adj[geta(p)].add(getb(q));
//adj[q.hashCode()].add(p);
}
}
}
match=new int[sum+1];
vis=new boolean[sum+1];
out.println("Case "+(++cas)+": "+maxmatch());
}
out.flush();
out.close();
}

}
class Pt{
int x,y,n;
Pt(int _x,int _y,int _n){
x=_x;y=_y;n=_n;
}
Pt(int hash,int _n){
n=_n;
y=hash%n;
x=hash/n;
}
public int hashCode(){
return x*n+y;
}
}
class InputReader{
public BufferedReader reader;
public StringTokenizer tokenizer;

public InputReader(InputStream stream){
reader = new BufferedReader(new InputStreamReader(stream), 32768);
tokenizer = null;
}

public String next(){
while(tokenizer == null || !tokenizer.hasMoreTokens()){
try{
tokenizer = new StringTokenizer(reader.readLine());
}catch (IOException e) {
throw new RuntimeException(e);
}
}
return tokenizer.nextToken();
}

public int nextInt() {
return Integer.parseInt(next());
}

public long nextLong() {
return Long.parseLong(next());
}

}

折腾了过长的时间,原因:
这不是通常意义上的可随意匹配的二分图。
既然是二分图,就有把节点分为两类的依据。
由题中给定的结合规则,一定是一个(x+y)为偶数的点与一个(x+y)为奇数的点相匹配,且是相邻点的匹配。
所以会将两类点分别加入两个表中,并进行hash操作节约存储空间。
“奇”的点总是不少于“偶”的点?