2022/8/19 题解
出去体检了,所以光荣抱灵
P4578 [FJOI2018]所罗门王的宝藏
-
点开标签一看:
图论
我:???
Solution
-
设操作完之后第 \(i\) 行的操作使第 \(i\) 行增加了 \(x_i\),第 \(j\) 列的操作使第 \(j\) 列减少了 \(y_j\),那么对于第 \(i\) 行第 \(j\) 列就有 \(x_i-y_j=v_{i,j}\),由此构造差分约束系统即可,求解的存在性即判负环,可使用
早就死了的\(\mathtt{SPFA}\); -
当然也有不用图论的方法,详情见 \(cyffff\) 大佬的题解;
AC Spfa
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int s=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch)){
s=s*10+int(ch-'0');
ch=getchar();
}
return s*f;
}
const int N=1e5+10;
int T,st;
int n,m,k;
int head[N],ver[N<<1],edge[N<<1],nxt[N<<1],tot=0;
void add(int x,int y,int z){
ver[++tot]=y,edge[tot]=z;
nxt[tot]=head[x],head[x]=tot;
return ;
}
bool ans;
int dist[N],ind[N];
bool vis[N];
void Spfa(){
memset(dist,0x3f3f3f3f,sizeof(dist));
memset(vis,0,sizeof(vis));
memset(ind,0,sizeof(ind));
dist[st]=0;
queue<int>q;
q.push(st),ind[st]=1;
while(q.size()){
int x=q.front();
q.pop();
vis[x]=0;
for(int i=head[x];i;i=nxt[i]){
if(dist[ver[i]]>dist[x]+edge[i]){
if(ind[ver[i]]>=n+m){
ans=0;
return ;
}
dist[ver[i]]=dist[x]+edge[i];
if(!vis[ver[i]]){
++ind[ver[i]];
vis[ver[i]]=1;
q.push(ver[i]);
}
}
}
}
return ;
}
int main(){
T=read();
while(T--){
memset(head,0,sizeof(head));
n=read(),m=read(),k=read();
tot=0;
st=n+m+1;
for(int i=1;i<=n+m;++i)
add(st,i,0);
int u,v,w;
for(int i=1;i<=k;++i){
u=read(),v=read(),w=read();
add(u,v+n,w);
add(n+v,u,-w);
}
ans=1;
Spfa();
printf("%s\n",ans?"Yes":"No");
}
return 0;
}
B.P3698 [CQOI2017]小Q的棋盘
- 又是贪心;
Solution
-
观察样例后,可以发现答案和这棵树上的最长链有关;
-
最终的贪心策略为走最长链,如果最长链走不完,就能走多少走多少;
如果最长链能走完,步数还有剩余的话,每两步可以走一个新点;
AC code
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int s=0,f=1;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch)){
s=s*10+int(ch-'0');
ch=getchar();
}
return s*f;
}
const int N=1e5+10;
int v,n;
int head[N],ver[N<<1],nxt[N<<1],tot=0;
int ans=0;
void add(int x,int y){
ver[++tot]=y;
nxt[tot]=head[x],head[x]=tot;
return ;
}
void dfs(int p,int f,int dep){
ans=max(ans,dep);
for(int i=head[p];i;i=nxt[i]){
if(ver[i]==f) continue;
dfs(ver[i],p,dep+1);
}
return ;
}
int main(){
v=read(),n=read();
int a,b;
for(int i=1;i<v;++i){
a=read(),b=read();
add(a+1,b+1);
add(b+1,a+1);
}
dfs(1,-1,1);
if(n<ans) printf("%d",n+1);
else printf("%d",min(v,ans+((n-ans+1)>>1)));
return 0;
}

浙公网安备 33010602011771号