最近在PAT上刷天梯赛的原题,切了几十道水题后做OJ上的题目居然连多组数据输入都差点忘了写= =
关注这道题很久了,一直不知道怎么跟网络流联系,后来学了白书上的状态压缩DP再看时怎么看都是一道很经典的状压DP。
后来为了寻找网络流的思路,还是手贱地搜了题解.....发现这种题居然还是一类题,叫最大点权独立集。
下面推荐一个博客:http://yzmduncan.iteye.com/blog/1149057
看完了之后秒懂,感觉就是一个赤裸裸的最大独立集的升级版啊。
然后果断建模跑板子,一次AC。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define rep(i, a, b) for(int i(a); i <= (b); ++i)
#define dec(i, a, b) for(int i(a); i >= (b); --i)
#define MP make_pair
const int INF = 1e9 + 7;
const int N = 100000 + 10;
const int M = 50000 + 10;
const int Q = 5000 + 10;
const int A = 300 + 10;
struct P{
int v,w,next;
}G[M];
int dis[Q],head[Q],a[A][A];
int dx[] = {0,0,1,-1},dy[] = {1,-1,0,0};
int tot,st,ed,n,m;
void init(){
tot = 0;
memset(head,-1,sizeof(head));
}
bool check(int x,int y){
if(x>=0 && x<m && y>=0 && y<n) return true;
else return false;
}
void add(int u,int v,int w){
G[tot].v = v;
G[tot].w = w;
G[tot].next = head[u];
head[u] = tot++;
swap(u,v);
G[tot].v = v;
G[tot].w = 0;
G[tot].next = head[u];
head[u] = tot++;
}
void build_G(){
st = m*n + 1,ed = st + 1;
for(int i=0 ;i<m ;i++){
for(int j=0 ;j<n ;j++){
if((i+j) & 1){
add(st,i*n+j,a[i][j]);
for(int k=0 ;k<4 ;k++){
int xx = i + dx[k];
int yy = j + dy[k];
if(check(xx,yy)){
add(i*n+j,xx*n+yy,INF);
}
}
}
else{
add(i*n+j,ed,a[i][j]);
}
}
}
}
bool bfs(void){
queue<int> que;
memset(dis,0,sizeof(dis));
dis[st] = 1;
que.push(st);
while(que.size()){
int u = que.front();
que.pop();
for(int i=head[u] ;i != -1 ;i = G[i].next){
int v = G[i].v,w = G[i].w;
if(dis[v] == 0 && w>0){
dis[v] = dis[u] + 1;
if(v == ed) return true;
que.push(v);
}
}
}
return false;
}
int dfs(int u,int low){
int uflow = 0;
if(u == ed) return low;
for(int i=head[u] ;i != -1 ;i = G[i].next){
int v = G[i].v,w = G[i].w;
if(dis[v] == dis[u] + 1 && w>0){
int flow = min(low-uflow,w);
flow = dfs(v,flow);
G[i].w -= flow;
G[i^1].w += flow;
uflow += flow;
if(uflow == low) break;
}
}
if(uflow == 0) dis[u] = 0;
return uflow;
}
int dinic(void){
int ans = 0;
while(bfs()){
ans += dfs(st,INF);
}
return ans;
}
void solve(int sum){
build_G();
int ans = dinic();
//printf("ans = %d sum = %d\n",ans,sum);
printf("%d\n",sum - ans);
}
int main(){
while(~scanf("%d%d",&m,&n)){
init();
int sum = 0;
for(int i=0 ;i<m ;i++){
for(int j=0 ;j<n ;j++){
scanf("%d",&a[i][j]);
sum += a[i][j];
}
}
solve(sum);
}
return 0;
}
因为1565数据规模很小,然后状压DP也能水一波~
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define rep(i, a, b) for(int i(a); i <= (b); ++i)
#define dec(i, a, b) for(int i(a); i >= (b); --i)
#define MP make_pair
const double eps= 1e-8 ;
const int INF = 1e9 + 7;
const int N = 100000 + 10;
const int M = 10000 + 10;
const int Q = 1000 + 50;
const int A = 20 + 5;
int dp[A][2*N];
int a[A][A];
int prime[2*N];
int n;
void input(){
for(int i=0 ;i<n ;i++){
for(int j=0 ;j<n ;j++){
scanf("%d",&a[i][j]);
}
}
}
void solve(){
memset(dp,0,sizeof(dp));
memset(prime,0,sizeof(prime));
int tot = 0,ed = 1 << n;
for(int i=0 ;i<ed ;i++){
if((i & (i<<1)) == 0)
prime[tot++] = i;
}
for(int i=0 ;i<n ;i++){
for(int j=0 ;j<tot ;j++){
int sum = 0;
for(int k=0 ;k<n ;k++){
if((prime[j] & (1<<k)) != 0){
sum += a[i][k];
}
}
dp[i][j] = sum;
if(i == 0) continue;
for(int k=0 ;k<tot ;k++){
if((prime[j] & prime[k]) == 0){
dp[i][j] = max(dp[i][j],dp[i-1][k] + sum);
}
}
}
}
int ans = 0;
for(int i=0 ;i<tot ;i++){
ans = max(ans,dp[n-1][i]);
}
printf("%d\n",ans);
}
int main(){
while(~scanf("%d",&n)){
input();
solve();
}
return 0;
}