Delicious Apples
题目大概:
给出一个有n个位置的环,有m个位置有苹果树,你的仓库在0的位置,你有一个大小为k的篮子,问最少走多少步,可以把所有苹果拿到位置0的仓库。
思路:
有3中拿的方式
1,从右边走,拿够苹果,然后直接返回。
2,从左边走,拿够苹果,然后返回。
3,绕一圈,把所有剩余苹果拿走。
显然,第三种方式,是最后剩余的苹果很少<=k个时,这样拿一圈,可以会走的步数少。但也有可能直接回去少,需要比较。
利用背包,把这三种方式模拟一遍。
感想:
如果改在直线上,仓库位置不固定,会怎么样,那就没有绕圈拿了,直接分析前两种情况就i选哪个了,所有,很多题,有环后,就复杂了一些。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
pair<int,int>G[maxn];
long long d[maxn];
long long dl[maxn],dr[maxn];
int cmp(pair<int,int> a,pair<int,int> b)
{
return a.first<b.first;
}
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
long long L;
int n,k;
memset(G,0,sizeof(G));
memset(d,0,sizeof(d));
memset(dl,0,sizeof(dl));
memset(dr,0,sizeof(dr));
scanf("%I64d%d%d",&L,&n,&k);
for(int i=0;i<n;i++)
{
scanf("%d%d",&G[i].first,&G[i].second);
}
sort(G,G+n,cmp);
int cnt=0;
for(int i=0;i<n;i++)
{
for(int j=1;j<=G[i].second;j++)
{
d[++cnt]=(long long)2*G[i].first;
}
}
for(int i=1;i<=cnt;i++)
{
if(i>k)
{
dl[i]=dl[i-k]+d[i];
}
else
{
dl[i]=d[i];
}
}
for(int i=cnt;i>=1;i--)
{
if(i+k<=cnt)
{
dr[i]=dr[i+k]+(2*L-d[i]);
}
else
{
dr[i]=(2*L-d[i]);
}
}
long long ans=0;
for(int i=0;i<=cnt;i++)
{
if(ans==0)ans=dl[i]+dr[i+1];
ans=min(ans,dl[i]+dr[i+1]);
}
for(int i=0;i+k+1<=cnt;i++)
{
ans=min(ans,dl[i]+dr[i+k+1]+L);
}
if(k>=cnt)ans=min(ans,L);
printf("%I64d\n",ans);
}
return 0;
}
Tricks Device
题目大概:
有一个迷宫,有n个房间,m条道。1为入口,n为出口。从1道n有最短路。
问最少切断几条道,可以使人不能从1走到n为最短路。
问最多切断几条道,还可以从1走最短路走到n。
思路:
求一遍1道n的最短路,并且维护1到n的最短路,最少变数为min,第二问答案就是m-min。
把图中的所有最短路的边重新建立最短路图,然后跑一边1到n的最大流。就是求的最小割。就是第一问的答案。
感想:
这是一个最短路和最大流结合的题目。
最大流,就考察了一个最小割转化为最大流来求,感觉难点还是求最短路的最少边,需要改变最短路的代码。
就是改动最短路的代码,既然可以求最少,也可以求最多,当然,也可以在最短路过程中维护其他的。
代码:
#include <bits/stdc++.h>
using namespace std;
#define RPEF( i , a , b ) for ( int i = a ; i <= b ; ++ i )
#define REP( i , n ) for ( int i = 0 ; i < n ; ++ i )
#define copy( a , x ) memcpy ( a , x , sizeof a )
typedef long long LL ;
const int MAXN = 3010 ;
const int MAXE = 100010;
const int MAXQ = 200010;
const int INF = 0x3f3f3f3f;
struct Edge {
int v , n ;
LL c ;
Edge ( int var = 0 , LL cap = 0 , int next = 0 ) :
v ( var ) , c ( cap ) , n ( next ) {}
} ;
struct netWork {
Edge edge[MAXE] ;
int adj[MAXN] , cntE ;
int cur[MAXN] , d[MAXN] , num[MAXN] , pre[MAXN] ;
bool vis[MAXN] ;
int Q[MAXQ] , head , tail ;
int s , t , nv ;
LL flow ;
void init () {
cntE = 0 ;
memset(adj,-1,sizeof(adj));
}
void addedge ( int u , int v , LL c , LL rc = 0 ) {
edge[cntE] = Edge ( v , c , adj[u] ) ;
adj[u] = cntE ++ ;
edge[cntE] = Edge ( u , rc , adj[v] ) ;
adj[v] = cntE ++ ;
}
void rev_Bfs () {
memset(vis,0,sizeof(vis));
memset(num,0,sizeof(num));
d[t] = 0 ;
vis[t] = 1 ;
head = tail = 0 ;
Q[tail ++] = t ;
num[0] = 1 ;
while ( head != tail ) {
int u = Q[head ++] ;
for ( int i = adj[u] ; ~i ; i = edge[i].n ) {
int v = edge[i].v ;
if ( vis[v] )
continue ;
vis[v] = 1 ;
d[v] = d[u] + 1 ;
++ num[d[v]] ;
Q[tail ++] = v ;
}
}
}
LL ISAP () {
copy ( cur , adj ) ;
rev_Bfs () ;
flow = 0 ;
int i , u = pre[s] = s ;
while ( d[s] < nv ) {
if ( u == t ) {
LL f = INF ;
int pos ;
for ( i = s ; i != t ; i = edge[cur[i]].v )
if ( f > edge[cur[i]].c )
f = edge[cur[i]].c , pos = i ;
for ( i = s ; i != t ; i = edge[cur[i]].v )
edge[cur[i]].c -= f , edge[cur[i] ^ 1].c += f ;
u = pos ;
flow += f ;
}
for ( i = cur[u] ; ~i ; i = edge[i].n )
if ( edge[i].c && d[u] == d[edge[i].v] + 1 )
break ;
if ( ~i ) {
cur[u] = i ;
pre[edge[i].v] = u ;
u = edge[i].v ;
}
else {
if ( 0 == ( -- num[d[u]] ) )
break ;
int mmin = nv ;
for ( i = adj[u] ; ~i ; i = edge[i].n )
if ( edge[i].c && mmin > d[edge[i].v] )
cur[u] = i , mmin = d[edge[i].v] ;
d[u] = mmin + 1 ;
++ num[d[u]] ;
u = pre[u] ;
}
}
return flow ;
}
} ;
netWork net ;
int n,m;
struct node1{
int v,next,w;
}edge[MAXE];
int id;
int head[MAXN];
void init1()
{
memset(head,-1,sizeof(head));
id=0;
}
void addedge(int u,int v,int w)
{
edge[id].v=v;
edge[id].w=w;
edge[id].next=head[u];
head[u]=id++;
edge[id].v=u;
edge[id].w=w;
edge[id].next=head[v];
head[v]=id++;
}
bool vis[MAXN];
int side[MAXN];
int dist[MAXN];
void spfa(int s)
{
memset(vis,false,sizeof(vis));
memset(dist,INF,sizeof(dist));
memset(side,INF,sizeof(side));
vis[s]=true;
dist[s]=0;
side[s]=0;
queue<int>que;
while(!que.empty()) que.pop();
que.push(s);
while(!que.empty())
{
int u=que.front();
que.pop();
vis[u]=false;
for(int i=head[u]; i!=-1; i=edge[i].next)
{
int v=edge[i].v;
if (dist[v]>dist[u]+edge[i].w)
{
dist[v]=dist[u]+edge[i].w;
side[v]=side[u]+1;
if (!vis[v])
{
vis[v]=true;
que.push(v);
}
}
if (dist[v]==dist[u]+edge[i].w)
{
side[v]=min(side[u]+1,side[v]);
if (!vis[v])
{
vis[v]=true;
que.push(v);
}
}
}
}
}
void getmap()
{
for(int i=1;i<=n;i++)
{
for(int j=head[i];j!=-1;j=edge[j].next)
{
int v=edge[j].v;
if(dist[v]==dist[i]+edge[j].w)
net.addedge(i,v,1);
}
}
}
int main()
{
while(scanf("%d%d",&n,&m)!=EOF)
{
int u,v,w;
init1();
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w);
}
spfa(1);
net.init();
getmap();
net.s=1;net.t=n;net.nv=net.t+1;
printf("%I64d %d\n",net.ISAP(),m-side[n]);
}
return 0;
}
Annoying problem
题目大概:
给出一棵树,n个点,(n-1)条边,然后给出q个操作,有一个集合s。每次操作后,给出s集合中所有点相连的最短路长度。
1 x 为s集合增加x节点,
2 x 把s集合中的x节点删除。
思路:
用dfs序和lca就可以解决这道题。
dis数组是给点到根的长度,lca(x,y)求x和ylca。
用了一个公式,dis【u】-dis【lca(x,u)】-dis【lca(y,u)】+dis【lca(x,y)】;
有点容斥的味道。
感想:
dfs序有很多树上的应用,算是一种简单树链剖分题的有效解决方法。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+50;
int cnt;
int head[maxn<<1];
struct poin
{
int to,w,next;
}edge[maxn<<1];
set<int>s;
int dis[maxn],dxu[maxn],be[maxn],d[maxn];
int vis[maxn];
int fa[maxn][25];
void add(int u,int v,int w)
{
edge[cnt].to=v;
edge[cnt].w=w;
edge[cnt].next=head[u];
head[u]=cnt++;
edge[cnt].to=u;
edge[cnt].w=w;
edge[cnt].next=head[v];
head[v]=cnt++;
}
int ans;
void init()
{
cnt=0;
ans=0;
memset(head,-1,sizeof(head));
memset(vis,0,sizeof(vis));
memset(dis,0,sizeof(dis));
memset(dxu,0,sizeof(dxu));
memset(fa,0,sizeof(fa));
s.clear();
}
void dfs(int u,int fat)
{
dxu[u]=++ans;
be[ans]=u;
for(int i=1; i<19; i++)
{
fa[u][i]=fa[fa[u][i-1]][i-1];
}
for(int i=head[u]; i!=-1; i=edge[i].next)
{
int v=edge[i].to;
int w=edge[i].w;
if(v==fat)continue;
d[v]=d[u]+1;
dis[v]=dis[u]+w;
fa[v][0]=u;
dfs(v,u);
}
}
int lca(int x,int y)
{
if(d[x]<d[y])swap(x,y);
for(int i=19; i>=0; i--)
{
if(d[fa[x][i]]>=d[y])
x=fa[x][i];
if(x==y)return x;
}
for(int i=19; i>=0; i--)
{
if(fa[x][i]!=fa[y][i])
{
x=fa[x][i];
y=fa[y][i];
}
}
return fa[x][0];
}
int solve(int u)
{
if( s.empty() ) return 0 ;
int x , y ;
set<int>::iterator iter;
iter = s.upper_bound(u) ;
if( iter == s.end() || iter == s.begin() )
{
x = be[ *s.begin() ] ;
y = be[ *s.rbegin()] ;
}
else
{
x = be[*iter] ;
iter-- ;
y = be[*iter] ;
}
u = be[u] ;
/*
cout<<"****"<<endl;
cout<<x<<" "<<y<<" "<<u<<endl;
cout<<dis[u]<<" "<<dis[lca(x,u)]<<" "<<dis[lca(y,u)]<<" "<<dis[lca(x,y)]<<endl;
cout<<dis[u]-dis[lca(x,u)]-dis[lca(y,u)]+dis[lca(x,y)]<<endl;
cout<<"****"<<endl;
*/
return dis[u]-dis[lca(x,u)]-dis[lca(y,u)]+dis[lca(x,y)] ;
}
int fl=0;
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
init();
int n,q;
scanf("%d%d",&n,&q);
int u,v,w;
for(int i=1; i<n; i++)
{
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
}
int sum=0;
printf("Case #%d:\n",++fl);
d[1]=1;
dfs(1,-1);
int flag,x;
while(q--)
{
scanf("%d%d",&flag,&x);
x=dxu[x];
if(flag==1)
{
if(!vis[x])
{
vis[x]=1;
sum+=solve(x);
s.insert(x);
}
}
else
{
if(vis[x])
{
vis[x]=0;
s.erase(x);
sum-=solve(x);
}
}
printf("%d\n",sum);
}
}
return 0;
}