坚决抵制长题面的题目!

首先观察到这个题目中,我们会发现,我们对于原图中的保护关系(一个点右边的点对于这个点也算是保护)

相当于一种依赖。

那么不难看出这个题实际上是一个最大权闭合子图模型。

我们直接对于权值为负数的边,\(S\rightarrow now\),流量是\(-a[i][j]\),表示打掉他要花这么多的代价。

对于权值为正的边,\(now \rightarrow T\) ,流量是\(a[i][j]\),表示如果割掉这个边,表示放弃他的收益。

(这里之所以\(S和T\)不能反过来,因为我们跑最小割的时候,是要保证S到T不连通,所以你要让负的权值与S相连,才会让依赖关系有意义)

对于每个点,向他保护的点连边,边权为\(inf\)。表示这个关系不能打破。

同时一个点右边的点,向这个点连边,流量也是\(inf\),因为右边的点要比左边的点先被打。

最后的答案就是\(正权值的sum - 最小割\)(总的收益,减去花费和舍去的。)

那么建出来图,我们会发现其实这个是有问题的。

因为可能存在环的情况。

(\(A保护B,B保护A\))

那么应该怎么办呢?

我们发现如果存在一个环,那么环能保护到的点,以及再往后的点,都是无敌的!

所以合法的点,就是从起点开始,找到所有的满足起点到这个点的所有路径都不经过环的 点。

那么这个可以通过拓扑排序来实现。

qwq

只需要一开始先把所有的依赖关系,跑一遍拓扑排序。

然后选出来有效的点,再建图就ok

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<map>
#include<set>
#define mk make_pair
#define ll long long
#define pb push_back
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
const int maxn = 3010;
const int maxm = 2e6+1e2;
const int inf = 1e9;
int n,m,cnt=1;
int point[maxn],nxt[maxm],to[maxm],val[maxm];
int h[maxn],in[maxn];
int s,t;
int a[maxn][maxn];
int sum;
int num;
int dfn[maxn];
int tag[maxn];
vector<int> v[maxn];
void init()
{
cnt=1;
memset(point,0,sizeof(point));
memset(in,0,sizeof(in));
}
void add(int x,int y)
{
nxt[++cnt]=point[x];
to[cnt]=y;
point[x]=cnt;
in[y]++;
}
void addedge(int x,int y,int w)
{
nxt[++cnt]=point[x];
to[cnt]=y;
val[cnt]=w;
point[x]=cnt;
}
void insert(int x,int y,int w)
{
addedge(x,y,w);
addedge(y,x,0);
}
queue<int> q;
bool bfs(int s)
{
memset(h,-1,sizeof(h));
h[s]=0;
q.push(s);
while (!q.empty())
{
int x = q.front();
q.pop();
for (int i=point[x];i;i=nxt[i])
{
int p=to[i];
if (h[p]==-1 && val[i]>0)
{
h[p]=h[x]+1;
q.push(p);
}
}
}
if (h[t]==-1) return false;
return true;
}
int dfs(int x,int low)
{
if (x==t || low==0) return low;
int totflow=0;
for (int i=point[x];i;i=nxt[i])
{
int p = to[i];
if (h[p]==h[x]+1 && val[i]>0)
{
int tmp = dfs(p,min(low,val[i]));
val[i]-=tmp;
val[i^1]+=tmp;
low-=tmp;
totflow+=tmp;
if (low==0) return totflow;
}
}
if (low>0) h[x]=-1;
return totflow;
}
int dinic()
{
int ans=0;
while (bfs(s))
{
ans=ans+dfs(s,inf);
}
return ans;
}
int getnum(int x,int y)
{
return (x-1)*m+y;
}
void tpsort()
{
while (!q.empty()) q.pop();
for (int i=1;i<=num;i++)
{
if (!in[i]) q.push(i),tag[i]=1,dfn[i]=1;
}
while (!q.empty())
{
int x = q.front();
q.pop();
for (int i=point[x];i;i=nxt[i])
{
int p=to[i];
in[p]--;
if (!in[p])
{
dfn[p]=dfn[x]+1;
q.push(p);
tag[p]=1;
}
}
}
}
int main()
{
n=read(),m=read();
num=n*m;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
a[i][j]=read();
int num = read();
for (int k=1;k<=num;k++)
{
int x=read(),y=read();
x++,y++;
v[getnum(i,j)].pb(getnum(x,y));
add(getnum(i,j),getnum(x,y));
}
if (j!=m) add(getnum(i,j+1),getnum(i,j));
}
tpsort();
init();
s=maxn-10;
t=s+1;
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
{
int now=getnum(i,j);
if(!tag[now]) continue;
if(a[i][j]>0) sum+=a[i][j];
for (int k=0;k<v[now].size();k++)
if (tag[v[now][k]]) insert(now,v[now][k],inf);
if (a[i][j]>0) insert(now,t,a[i][j]);
else insert(s,now,-a[i][j]);
}
for (int i=1;i<=n;i++)
{
for (int j=1;j<=m;j++)
{
int now = getnum(i,j);
int ri = getnum(i,j+1);
if (j==m) continue;
if (!tag[now] || !tag[ri]) continue;
if (dfn[ri]>dfn[now]) swap(now,ri);
insert(ri,now,inf);
}
}
cout<<sum-dinic();
return 0;
}

最新文章

  1. Lua学习笔记一
  2. 练习1-21:编写程序entab,将空格串替换为最少数量的制表符和空格。。。(C程序设计语言 第2版)
  3. 什么是Java实例初始化块
  4. bootstrap-9
  5. FluentData,它是一个轻量级框架,关注性能和易用性。
  6. 快速幂取模 POJ 3761 bubble sort
  7. “main cannot be resolved or is not a field”解决方案
  8. PHP学习之[第08讲]数据库MySQL基础之增删改查
  9. 嵌入式平台组件白盒测试gcov、lcov和genhtml 使用指导
  10. 一致性hash和虚拟节点
  11. JAVAEE企业级应用开发浅谈第二辑:MVC和三层架构
  12. windows server 2003 远程桌面最大连接数调整与windows 2008远程桌面后,本地帐号自动锁定
  13. JAVA开发环境搭建(Mac)
  14. (栈 注意格式)P1739 表达式括号匹配 洛谷
  15. Win userAccountControl 基本属性
  16. pyinstaller打包程序 带图片
  17. 自学Linux Shell11.4-重定向输入输出
  18. gulp和webpack的区别
  19. c++ 继承(二)
  20. java实现图片上传功能,并返回图片保存路径

热门文章

  1. redhat9 linux 网卡无法激活排障
  2. Error establishing a database connection!
  3. LeetCode入门指南 之 二分搜索
  4. blender skin modifier 太好玩了
  5. SAR总结
  6. Spring中使用@within与@target的一些区别
  7. GIT:创建、查看分支命令(git branch -vv)
  8. 一行Java代码实现游戏中交换装备
  9. python-引用/模块
  10. gentoo(贱兔) Linux作业系统的基本使用