版权声明:小蒟蒻的博客转载也请注明出处哦 https://blog.csdn.net/qq_42835823/article/details/83388086
最短路计数
统计最短路
次短路径Roadblocks
矩阵游戏
The Perfect Stall 完美的牛栏
奶牛浴场
【以上均出自WOJ】
最短路计数
最短路
设一个ans数组记录当前点的最短路有几条。
满足条件更新。
松弛的时候重新更新。
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return x*f;
}
struct edge{
int v,w,nxt;
}e[4000010];
int first[2010],cnt=0;
inline void add(int u,int v,int w){
e[++cnt].v=v;e[cnt].w=w;
e[cnt].nxt=first[u];first[u]=cnt;
}
int n,m,g[2005][2005],dis[2005],vis[2005],ans[2005];
void dijkstra(){
priority_queue< pair<int,int> >q;
memset(dis,0x3f,sizeof(dis));
dis[1]=0;ans[1]=1;
q.push(make_pair(0,1));
while(!q.empty()){
int u=q.top().second;q.pop();
if(vis[u])continue;
vis[u]=1;
for(int i=first[u];i;i=e[i].nxt){
int v=e[i].v;
if(dis[v]>dis[u]+e[i].w){
dis[v]=dis[u]+e[i].w;
q.push(make_pair(-dis[v],v));
ans[v]=ans[u];
}
else if(dis[v]==dis[u]+e[i].w)ans[v]+=ans[u];
}
}
}
int main(){
n=read();m=read();
for(int i=1;i<=m;i++){
int u,v,w;
u=read();v=read();w=read();
if(!g[u][v]||w<g[u][v])g[u][v]=w;
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(g[i][j])add(i,j,g[i][j]);
dijkstra();
if(dis[n]==0x3f3f3f3f)printf("No answer");
else printf("%d %d",dis[n],ans[n]);
return 0;
}
统计最短路
最短路
判断一条边是否在最短路上。
双向dijkstra即可:dis_1[u]+e[i].w+dis_2[v]==dis_1[n];
不过此题只用判零环,用一个flag数组就好。
#include<bits/stdc++.h>
using namespace std;
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return x*f;
}
struct edge{
int v,w,nxt;
}e[200010];
int first[5010],cnt=0;
inline void add(int u,int v,int w){
e[++cnt].v=v;e[cnt].w=w;
e[cnt].nxt=first[u];first[u]=cnt;
}
const int mod=1000000009;
int n,m,dis[5005],vis[5005],ans[5005],flag[5005];
void dijkstra(){
priority_queue< pair<int,int> >q;
memset(dis,0x3f,sizeof(dis));
dis[1]=0;ans[1]=1;
q.push(make_pair(0,1));
while(!q.empty()){
int u=q.top().second;q.pop();
if(vis[u])continue;
vis[u]=1;
for(int i=first[u];i;i=e[i].nxt){
int v=e[i].v;
if(dis[v]>dis[u]+e[i].w){
dis[v]=dis[u]+e[i].w;
if(flag[u]||!e[i].w)flag[v]=1;
else flag[v]=0;
q.push(make_pair(-dis[v],v));
ans[v]=ans[u];
}
else if(dis[v]==dis[u]+e[i].w)ans[v]=(ans[v]+ans[u])%mod;
}
}
}
int main(){
n=read();m=read();
for(int i=1;i<=m;i++){
int u,v,w;
u=read();v=read();w=read();
add(u,v,w);add(v,u,w);
}
dijkstra();
if(flag[n])printf("-1");
else printf("%d",ans[n]);
return 0;
}
次短路径Roadblocks
次短路
次短路径和最短路径至少有一条边不同,且那条边一定不在最短路径上,
那我就双向dijkstra,枚举所有的边,再求这条边的起点到1,终点到n的最短路径,加上这条边权值,判断一下是否为最短路,再取maxans。
#include<bits/stdc++.h>
using namespace std;
struct edge{
int u,v,w,nxt;
}e[200010];
int first[5005],cnt=0;
inline void add(int u,int v,int w){
e[++cnt].u=u;e[cnt].v=v;e[cnt].w=w;
e[cnt].nxt=first[u];first[u]=cnt;
}
int n,m,ans;
int vis[5005],dis1[5005],dis2[5005];
void dijkstra_1(){
priority_queue< pair<int,int> >q;
q.push(make_pair(0,1));
memset(dis1,0x3f,sizeof(dis1));
memset(vis,0,sizeof(vis));
dis1[1]=0;
while(!q.empty()){
int u=q.top().second;q.pop();
if(vis[u])continue;
vis[u]=0;
for(int i=first[u];i;i=e[i].nxt){
int v=e[i].v;
if(dis1[v]>dis1[u]+e[i].w){
dis1[v]=dis1[u]+e[i].w;
q.push(make_pair(-dis1[v],v));
}
}
}
}
void dijkstra_2(){
priority_queue< pair<int,int> >q;
q.push(make_pair(0,n));
memset(dis2,0x3f,sizeof(dis2));
memset(vis,0,sizeof(vis));
dis2[n]=0;
while(!q.empty()){
int u=q.top().second;q.pop();
if(vis[u])continue;
vis[u]=0;
for(int i=first[u];i;i=e[i].nxt){
int v=e[i].v;
if(dis2[v]>dis2[u]+e[i].w){
dis2[v]=dis2[u]+e[i].w;
q.push(make_pair(-dis2[v],v));
}
}
}
}
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=m;i++){
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);add(v,u,w);
}
dijkstra_1();
dijkstra_2();
ans=0x7fffffff;
for(int i=1;i<m*2;i++){
int r=dis1[e[i].u]+dis2[e[i].v]+e[i].w;
if(r!=dis1[n]&&r<ans)ans=r;
}
printf("%d",ans);
return 0;
}
矩阵游戏
二分图
二分图完全匹配问题
对每一个黑点,我们都建一条横坐标连向纵坐标的边,
然后跑二分图匹配。
推导 最终状态是(1,1)(2,2)…(n,n)都有一个点
我们把点看成匹配边的话,就是每行和每列都做到了匹配
换言之就是N个行和N个列都有匹配时,一定能转换成最终状态
#include<bits/stdc++.h>
using namespace std;
struct edge{
int u,v,nxt;
}e[1000010];
int first[4010],cnt=0;
inline void add(int u,int v){
e[++cnt].u=u;e[cnt].v=v;
e[cnt].nxt=first[u];first[u]=cnt;
}
int n,t,vis[4010],match[4010],ans=0;
bool dfs(int x){
for(int i=first[x];i;i=e[i].nxt){
int v=e[i].v;
if(vis[v])continue;
vis[v]=1;
if(!match[v]||dfs(match[v])){
match[v]=x;
return 1;
}
}
return 0;
}
int main(){
scanf("%d",&t);
while(t--){
memset(match,0,sizeof(match));
memset(first,0,sizeof(first));
ans=0;
scanf("%d",&n);
int c;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
scanf("%d",&c);
if(c)add(i,j+n);
}
for(int i=1;i<=n;i++){
memset(vis,0,sizeof(vis));
if(dfs(i))ans++;
}
if(ans==n)printf("Yes\n");
else printf("No\n");
}
return 0;
}
The Perfect Stall 完美的牛栏
二分图
裸二分图最大匹配
#include<bits/stdc++.h>
using namespace std;
int n,m,a[205][205],vis[405],mat[405],ans=0;
bool dfs(int x){
for(int i=1;i<=m;i++){
if(!a[x][i]||vis[i])continue;
vis[i]=1;
if(!mat[i]||dfs(mat[i])){
mat[i]=x;
return 1;
}
}
return 0;
}
int main(){
scanf("%d%d",&n,&m);
int c,d;
for(int i=1;i<=n;i++){
scanf("%d",&c);
while(c--){
scanf("%d",&d);
a[i][d]=1;
}
}
for(int i=1;i<=n;i++){
memset(vis,0,sizeof(vis));
ans+=dfs(i);
}
printf("%d",ans);
return 0;
}
奶牛浴场
矩阵DP
qwq ^ __ ^ qwq的算法一
#include<bits/stdc++.h>
using namespace std;
struct node{
int x,y;
}a[5010];
inline int Sort_5(node e,node f){
return e.y<f.y;
}
inline int Sort_3(node e,node f){
return e.y>f.y;
}
inline int Sort_1(node e,node f){
return e.x<f.x;
}
int n,m,t,ans;
void work(){
for(int i=1;i<=t;i++){//枚举左端点(右端点)
int l=0,r=n;
for(int j=i+1;j<=t;j++){//枚举产奶点,卡上下界
if(a[j].x>=r||a[j].x<=l)continue;
ans=max(ans,abs(a[j].y-a[i].y)*(r-l));//不减一
if(a[j].x<a[i].x)l=a[j].x;
else r=a[j].x;
if(l>=r-1)break;
}
}
}
int main(){
scanf("%d%d%d",&n,&m,&t);
if(t==0){
printf("%d",n*m);
return 0;
}
for(int i=1;i<=t;i++){
scanf("%d%d",&a[i].x,&a[i].y);
}
a[++t].x=0;a[t].y=0;a[++t].x=n;a[t].y=m;
a[++t].x=0;a[t].y=m;a[++t].x=n;a[t].y=0;//需要添加的点不仅仅是左下右上,4个顶角都要
sort(a+1,a+t+1,Sort_1);
for(int i=2;i<=t;i++)ans=max(ans,m*(a[i].x-a[i-1].x));
sort(a+1,a+t+1,Sort_5);
work();
sort(a+1,a+t+1,Sort_3);
work();
printf("%d",ans);
return 0;
}