1. 程式人生 > >20181025小結-1

20181025小結-1

最短路計數
統計最短路
次短路徑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;
}