20181025小結-1
阿新 • • 發佈:2018-11-01
最短路計數
統計最短路
次短路徑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;
}