标签:cnt leq 省选 vis int 2021 include 联考 dis
一、题目
二、解法
首先发现整个矩阵其实之和最后一行最后一列(我称之为边角)有关,如果确定了他们整个矩阵就确定了。考虑调整法,我们先让边角全为 \(0\),那么得到的矩阵 \(a\) 很可能是不合法的,我们考虑调整它。
调整有一个原则就是保持 \(a\) 能构造出 \(b\),调整 \(a\) 的单个元素是困难的。考虑调整一整行或者一整列,奇数位置加 \(x\) 偶数位置减 \(x\),这样调整 \(b\) 是不会变的,而且因为这样做可以调整出所有的边角可能情况,而边角的状态和整个矩阵的状态一一对应,所以这种调整方法是充分的。具体来说有下面的不等式,\(r_i,c_j\) 分别表示行和列的调整值:
\[0\leq \pm r_i\pm c_j+a_{i,j}\leq 10^6 \]解决这个不等式很容易想到差分约束,但是会出现 \(x\leq -y+c\) 之类的不等式,这时候可以拆一个表示负数权值的点出来,然后连成对称图就可以保证某点正点和负点的权值相同,但是要讨论很多情况。
还有一个更简介的方法是把原图进行二染色,让每种颜色对应一种等式:
\[row\ \ \ \begin{matrix}+&-&+&-\\-&+&-&+\\+&-&+&-\\-&+&-&+\end{matrix} \]\[col\ \ \ \begin{matrix}-&+&-&+\\+&-&+&-\\-&+&-&+\\+&-&+&-\end{matrix} \]- 若 \(i+j\) 为奇数:\(0\leq r_i-c_j+a_{i,j}\leq 10^6\)
- 若 \(i+j\) 为偶数:\(0\leq -r_i+c_j+a_{i,j}\leq 10^6\)
然后用 \(\tt spfa\) 跑图判负环即可,判负环的好方法:维护到每个点的最短路径长度,如果 \(\geq\) 总点数就一定有负环。
#include <cstdio>
#include <vector>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
const int M = 605;
#define ll long long
int read()
{
int x=0,f=1;char c;
while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
int T,n,m,cnt[M],vis[M];ll dis[M],a[M][M],b[M][M];
struct node
{
int v;ll c;
};vector<node> g[M];
void link(int u,int v,ll c)
{
g[u].push_back({v,c});
}
void spfa()
{
queue<int> q;
memset(dis,0x3f,sizeof dis);
memset(vis,0,sizeof vis);
memset(cnt,0,sizeof cnt);
dis[1]=cnt[1]=0;vis[1]=1;q.push(1);
while(!q.empty())
{
int u=q.front();q.pop();
vis[u]=0;
for(int i=0;i<g[u].size();i++)
{
node x=g[u][i];
if(dis[x.v]>dis[u]+x.c)
{
dis[x.v]=dis[u]+x.c;
cnt[x.v]=cnt[u]+1;
if(cnt[x.v]>=n+m) {puts("NO");return ;}
if(!vis[x.v]) vis[x.v]=1,q.push(x.v);
}
}
}
puts("YES");
for(int i=1;i<=n;i++,puts(""))
for(int j=1;j<=m;j++)
{
ll t=dis[i]-dis[j+n];
if((i+j)%2)
printf("%lld ",t+a[i][j]);
else
printf("%lld ",-t+a[i][j]);
}
}
void work()
{
memset(a,0,sizeof a);
n=read();m=read();
for(int i=1;i<=n+m;i++)
g[i].clear();
for(int i=1;i<n;i++)
for(int j=1;j<m;j++)
b[i][j]=read();
for(int i=n-1;i>=1;i--)
for(int j=m-1;j>=1;j--)
a[i][j]=b[i][j]-a[i+1][j]
-a[i][j+1]-a[i+1][j+1];
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if((i+j)%2)
{
//0<=ri-cj+aij<=1e6
//cj<=ri+aij,ri<=cj+1e6-aij
link(i,j+n,a[i][j]);
link(j+n,i,1e6-a[i][j]);
}
else
{
//0<=-ri+cj+aij<=1e6
//ri<=cj+aij,cj<=ri+1e6-aij
link(j+n,i,a[i][j]);
link(i,j+n,1e6-a[i][j]);
}
}
spfa();
}
signed main()
{
T=read();
while(T--) work();
}
标签:cnt,leq,省选,vis,int,2021,include,联考,dis 来源: https://www.cnblogs.com/C202044zxy/p/15026223.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。