让我看到你们的双手
感觉今天的考试敲得又多,又难想。。。。
1.幻想乡的异变
【解题报告】
大概思路就是我们先过一遍SPFA,然后根据dis[]来dfs确定网络流的边。
正确性(可能)显然。
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define N 405
#define M 100005
#define inf 0x3f3f3f3f
int n,m,a,b,c,dis[N],vis[N],f[N];
int head[N],num=1;
struct Edge
{
int v,next,flow,cap,w;
}e[2*M];
void adde(int u,int v,int w)
{
e[++num].v=v;
e[num].next=head[u];
e[num].w=w;
e[num].flow=0;
head[u]=num;
}
void spfa()
{
deque<int> q;
q.push_back(1);
memset(dis,inf,sizeof(dis));
dis[1]=0;vis[1]=1;
while(!q.empty())
{
int u=q.front();q.pop_front();
vis[u]=0;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].v;
if(dis[v]>dis[u]+e[i].w)
{
dis[v]=dis[u]+e[i].w;
if(!vis[v])
{
vis[v]=1;
if(!q.empty())
{
if(dis[v]>dis[q.front()]) q.push_back(v);
else q.push_front(v);
}
else q.push_back(v);
}
}
}
}
}
struct Dinic
{
int s,t,d[N];
bool bfs()
{
queue<int> q;
memset(d,0,sizeof(d));
q.push(s);
d[s]=1;
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].v;
if(e[i].cap>e[i].flow&&!d[v])
{
d[v]=d[u]+1;
q.push(v);
}
}
}
if(d[t]) return true;
else return false;
}
int dfs(int u,int a)
{
if(u==t||a==0) return a;
int flow=0,f;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].v;
if(d[v]==d[u]+1&&(f=dfs(v,min(a,e[i].cap-e[i].flow)))>0)
{
e[i].flow+=f;
e[i^1].flow-=f;
flow+=f;
a-=f;
if(a==0) return flow;
}
}
if(!flow)d[u]=-1;
return flow;
}
int maxflow()
{
int flow=0;
while(bfs()) flow+=dfs(s,inf);
return flow;
}
}date;
void dfs(int u)
{
vis[u]=1;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].v;
if(e[i].w+dis[u]==dis[v])
{
e[i].cap++;
e[i^1].cap=0;
if(!vis[v]) dfs(v);
}
}
}
int main()
{
freopen("change.in","r",stdin);
freopen("change.out","w",stdout);
scanf("%d%d",&n,&m);
date.s=1,date.t=n;
for(int i=1;i<=m;++i)
{
scanf("%d%d%d",&a,&b,&c);
adde(a,b,c);
adde(b,a,inf);
}
spfa();
memset(vis,0,sizeof(vis));
dfs(1);
printf("%d\n",date.maxflow());
return 0;
}
2.幻想乡的符卡
【解题报告】
还没懂
代码如下:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
using namespace std;
#define N 8000
#define inf 0x3f3f3f3f
int head[N],num=1,k;
int P[N],T[N],L[N],prime[1500],ptot,n,sum,ha,pos;
struct Edge
{
int v,next,flow,cap;
}e[100*N];
void add_edge(int i,int j,int w)
{
e[++num].v=j;
e[num].next=head[i];
e[num].cap=w;
e[num].flow=0;
head[i]=num;
}
void add(int u,int v,int w)
{
add_edge(u,v,w);
add_edge(v,u,0);
}
struct Dinic
{
int s,t,d[N];
bool bfs(int mid,int pos)
{
queue<int>q;
memset(d,0,sizeof(d));
q.push(s);
d[s]=1;
while(!q.empty())
{
int u=q.front();q.pop();
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].v;
if(T[v]==1&&v!=pos) continue;
if(e[i].cap>e[i].flow&&!d[v]&&L[v]<=mid)
{
d[v]=d[u]+1;
q.push(v);
}
}
}
if(d[t]) return true;
else return false;
}
int dfs(int u,int a,int mid,int pos)
{
if(u==t||a==0) return a;
int flow=0,f;
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].v;
if(T[v]==1&&pos!=v) continue;
if(L[v]<=mid&&d[v]==d[u]+1&&(f=dfs(v,min(a,e[i].cap-e[i].flow),mid,pos))>0)
{
e[i].flow+=f;
e[i^1].flow-=f;
flow+=f;
a-=f;
if(a==0)return flow;
}
}
if(!flow)d[u]=-10;
return flow;
}
int maxflow(int mid,int pos)
{
int flow=0,ans=0;
for(int i=2;i<=num;i++) e[i].flow=0;
while(bfs(mid,pos)) flow+=dfs(s,inf,mid,pos);
return flow;
}
}date;
void init()
{
prime[++ptot]=2;
for(int i=3;i<=10000;i++)
{
int j;
for(j=2;j*j<=i;j++)
if(i%j==0) break;
if(j*j>i)prime[++ptot]=i;
}
}
bool isprime(int x)
{
for(int i=1;prime[i]*prime[i]<=x;i++)
if(x%prime[i]==0) return false;
return true;
}
void pre()
{
for(int i=1;i<=n;i++)
{
if(T[i]%2==0)continue;
for(int j=1;j<=n;j++)
{
if(T[j]%2==1) continue;
if(isprime(T[i]+T[j])) add(i,j,inf);
}
}
}
bool check(int mid)
{
ha=0;int maxx=-1;
for(int i=1;i<=n;i++)
{
if(L[i]<=mid&&T[i]!=1)ha+=P[i];
if(L[i]<=mid&&T[i]==1)
{
if(P[i]>maxx)
{
maxx=P[i];
pos=i;
}
}
}
ha+=maxx;
if(ha-date.maxflow(mid,pos)>=k) return true;
else return false;
}
int main()
{
// freopen("card.in","r",stdin);
// freopen("card.out","w",stdout);
init();
date.s=0,date.t=1200;
L[0]=-1,L[1200]=-1;
scanf("%d%d",&n,&k);
int st=inf,ed=0;
for(int i=1;i<=n;++i)
{
scanf("%d%d%d",&P[i],&T[i],&L[i]);
st=min(st,L[i]);
ed=max(ed,L[i]);
if(T[i]%2==1) add(date.s,i,P[i]);
else add(i,date.t,P[i]);
}
pre();
int l=st,r=ed,ans=-1;
while(l<r)
{
if(r-l==1)
{
if(check(l)) {r=l,ans=1;break;}
if(check(r)) {l=r,ans=1;break;}
}
int mid=(l+r)>>1;
if(check(mid)) ans=1,r=mid;
else l=mid+1;
}
if(check(l)) ans=1;
if(ans!=-1) printf("%d\n",l);
else printf("-1\n");
return 0;
}
3.幻想乡的例大祭
【解题报告】
互相到达这个条件我们用Tarjan来解决,。
至于最短路嘛SPFA如果不加SLF优化的话会被无情地卡掉。
代码如下:
#include<queue>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 300000
using namespace std;
int n,m;
int e[M],ind[M],nex[M],lon[M],tot;
long long dis[M];
long long cost[M];
int dfn[M],low[M],con[M],sta[M],vis[M],top,tim;
void add(int a,int b,int c)
{
nex[++tot]=ind[a];
e[ind[a]=tot]=b;
lon[tot]=c;
}
void tarjan(int v)
{
dfn[v]=low[v]=++tim;
vis[sta[++top]=v]=1;
for(int i=ind[v];i;i=nex[i])
{
if(!dfn[e[i]])
{
tarjan(e[i]);
low[v]=min(low[v],low[e[i]]);
}
else if(vis[e[i]]) low[v]=min(low[v],dfn[e[i]]);
}
if(dfn[v]==low[v])
for(int now=0;now!= v;)
{
vis[now=sta[top--]]=0;
con[now]=v;
}
}
void spfa()
{
deque<int> qu;
memset(vis,0,sizeof vis);
memset(dis,-1,sizeof dis);
memset(cost,-1,sizeof cost);
qu.push_back(1);dis[1]=0,cost[1]=0;
while(!qu.empty())
{
int v=qu.front();
qu.pop_front();
vis[v]=0;
for(int i=ind[v];i;i=nex[i])
{
int cc=con[e[i]]==con[v]?cost[v]+1:cost[v];
if(cost[e[i]]>cc||cost[e[i]]==-1||(dis[e[i]]>dis[v]+lon[i]&&cost[e[i]]==cc)||(dis[e[i]]==-1&&cost[e[i]]==cc))
{
cost[e[i]]=cc;
dis[e[i]]=dis[v]+lon[i];
if(!vis[e[i]])
{
vis[e[i]]=1;
if(!qu.empty())
{
if(dis[e[i]]>dis[qu.front()]) qu.push_back(e[i]);
else qu.push_front(e[i]);
}
else qu.push_back(e[i]);
}
}
}
}
}
int main()
{
freopen("festival.in","r",stdin);
freopen("festival.out","w",stdout);
int n,m,a,b,c;
scanf("%d %d",&n,&m);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&a,&b,&c);
add(b,a,c);
}
for(int i=1;i<=n;i++)
if(!con[i]) tarjan(i);
spfa();
for(int k=2;k<=n;k++)
{
if(dis[k]==dis[0]) printf("-1\n");
else printf("%I64d %I64d\n",cost[k],dis[k]);
}
return 0;
}