很显然就是一个最大流题目。
不过进行建模不好想
需要用到一个拆点操作,所谓拆点就是将一个点转化为一条边,中间流量是1
建立超级源点跟超级汇点。
源点跟银行相连接,图的边界点跟汇点相连接。
从而套用模板计算最大流即可,但令我困惑的是自己的模板好像写错了,但是不应该呀,过了别的题了呀,难道是因为那几道题目数据量太弱吗?很不理解,最后套用别人模板给AC了:
Dinic
#include <iostream>
#include <string.h>
#include <queue>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAX_N=10000; //顶点数上限
const int MAX_M=500000; //总的边数上限
struct edge{
int v,c,next; //v指另一个顶点,c表示容量。
}e[MAX_M];
int p[MAX_N],eid;
int n,m;
int S,T; //S是源点,T是汇点。
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
void insert(int u,int v,int c){ //插入一条从u向v,容量为c的弧。
e[eid].v=v;
e[eid].next=p[u];
e[eid].c=c;
p[u]=eid++;
}
void addedge(int u,int v,int c){ //用insert插入网络中的弧
insert(u,v,c);
insert(v,u,0); //插入一条反方向,当前容量为0的弧
}
void init(){
memset(p,-1,sizeof(p));
eid=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
int x,y;
x=(i-1)*m+j;
y=x+m*n;
addedge(x,y,1);
for(int k=0;k<4;k++){
int l=i+dx[k];
int r=j+dy[k];
if(l>=1&&l<=n&&r>=1&&r<=m){
x=(l-1)*m+r;
addedge(y,x,1);
}else{
addedge(y,T,1);
}
}
}
}
}
int d[MAX_N]; //存储每个顶点的层次
bool bfs(){
memset(d,-1,sizeof(d));
queue<int> q;
q.push(S);
d[S]=0;
while(!q.empty()){
int u=q.front();
q.pop();
for(int i=p[u];i!=-1;i=e[i].next){
int v=e[i].v;
if(e[i].c>0&&d[v]==-1){
q.push(v);
d[v]=d[u]+1;
}
}
}
return (d[T]!=-1);
}
int dfs(int u,int flow){ //flow表示当前搜索分支的流量上限
if(u==T){
return flow;
}
int res=0;
for(int i=p[u];i!=-1;i=e[i].next){
int v=e[i].v;
if(e[i].c>0&&d[u]+1==d[v]){
int tmp=dfs(v,min(flow,e[i].c)); // 递归计算顶点 v,用 c(u, v) 来更新当前流量上限
flow-=tmp;
e[i].c-=tmp;
res+=tmp;
e[i^1].c+=tmp; // 修改反向弧的容量
if(flow==0){ // 流量达到上限,不必继续搜索了
break;
}
}
}
if(res==0){ // 当前没有经过顶点 u 的可行流,不再搜索顶点 u
d[u]=-1;
}
return res;
}
int dinic(){ // 函数返回值就是最大流的结果
int res=0;
while(bfs()){
res+=dfs(S,INF); // 初始流量上限为 INF
}
return res;
}
int main() {
int cas;
scanf("%d",&cas);
while(cas--){
int bian;
scanf("%d%d%d",&n,&m,&bian);
S=0;
T=n*m*2+1;
init();
for(int i=0;i<bian;i++){
int x,y;
scanf("%d%d",&x,&y);
addedge(S,(x-1)*m+y,1);
}
if(bian==dinic()){
printf("possible\n");
}else{
printf("not possible\n");
}
}
return 0;
}
ISAP:
#include <iostream>
#include <string.h>
#include <queue>
#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAX_N=10000; //顶点数上限
const int MAX_M=500000; //总的边数上限
struct edge{
int v,c,next; //v指另一个顶点,c表示容量。
}e[MAX_M];
int p[MAX_N],eid;
int S,T; //S是源点,T是汇点。
int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};
void insert(int u,int v,int c){ //插入一条从u向v,容量为c的弧。
e[eid].v=v;
e[eid].next=p[u];
e[eid].c=c;
p[u]=eid++;
}
void addedge(int u,int v,int c){ //用insert插入网络中的弧
insert(u,v,c);
insert(v,u,0); //插入一条反方向,当前容量为0的弧
}
void init(int n,int m){
memset(p,-1,sizeof(p));
eid=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
int x,y;
x=(i-1)*m+j;
y=x+m*n;
addedge(x,y,1);
for(int k=0;k<4;k++){
int l=i+dx[k];
int r=j+dy[k];
if(l>=1&&l<=n&&r>=1&&r<=m){
x=(l-1)*m+r;
addedge(y,x,1);
}else{
addedge(y,T,1);
}
}
}
}
}
int gap[MAX_N];
int dis[MAX_N];
int cur[MAX_N];
int pre[MAX_N];
int rec[MAX_N];
void BFS()
{
int i;
for(i = 0; i <= T; i++) dis[i] = INF;
queue<int> q;
q.push(T);
dis[T] = 0;
while(!q.empty())
{
int u = q.front();
q.pop();
gap[dis[u]]++;
for(i = p[u]; i != -1; i = e[i].next)
{
int v = e[i].v;
if(dis[v] == INF && e[i^1].c)
{
dis[v] = dis[u] + 1;
q.push(v);
}
}
}
}
int SAP()
{
int i;
int u = pre[S] = S, Maxflow = 0, flow = INF;
for(i = 0; i <= T; i++)//这里 T 为最大顶点编号
{
gap[i] = 0;
cur[i] = p[i];
}
BFS();
while(dis[S] <= T)
{
if(u == T)
{
Maxflow += flow;
for(; u != S; u = pre[u])
{
e[rec[u]].c -= flow;
e[rec[u]^1].c += flow;
}
flow = INF;
}
for(i = cur[u]; i != -1; i = e[i].next)
{
int v = e[i].v;
if(e[i].c && dis[u] == dis[v] + 1)
{
flow = min(flow, e[i].c);
pre[v] = u;
rec[v] = i;
cur[u] = i;//当前弧优化
u = v;
break;
}
}
if(i == -1)
{
int mindis = T + 1;//T是顶点数
if((--gap[dis[u]]) == 0) break;//间隙优化
for(i = cur[u] = p[u]; i != -1; i = e[i].next)
{
if(e[i].c && mindis > dis[e[i].v])
{
mindis = dis[e[i].v];
}
}
gap[dis[u] = mindis+1]++;
u = pre[u];
}
}
return Maxflow;
}
int main() {
int cas;
scanf("%d",&cas);
while(cas--){
int bian;
int n,m;
scanf("%d%d%d",&n,&m,&bian);
S=0;
T=n*m*2+1;
init(n,m);
for(int i=0;i<bian;i++){
int x,y;
scanf("%d%d",&x,&y);
addedge(S,(x-1)*m+y,1);
}
if(bian==SAP()){
printf("possible\n");
}else{
printf("not possible\n");
}
}
return 0;
}