20181025小结-1

版权声明:小蒟蒻的博客转载也请注明出处哦 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;
}

猜你喜欢

转载自blog.csdn.net/qq_42835823/article/details/83388086