@Metralix
2018-03-08T14:33:28.000000Z
字数 3989
阅读 1020
最短路
题目大意
有三个杯子它们的容量分别是a,b,c, 并且初始状态下第一个和第二个是空的, 第三个杯子是满水的。可以把一个杯子的水倒入另一个杯子,当然,当被倒的杯子满了或者倒的杯子水完了,就不能继续倒了。
你的任务是写一个程序计算出用最少的倒水量,使得其中一个杯子里有d升水。如果不能倒出d升水的话,那么找到一个d' < d ,使得d' 最接近d。
解题思路
因为共有3个水杯, 根据每一杯的水量v1,v2,v3, 可以得到一个状态state(v1,v2,v3);
为了方便进行dfs搜索的状态转移,可以用两个三维数组volume[3], state[3]分别表示三个杯子的容量和状态。然后会有倒水的动作,可以从第1个杯子倒入第2,3个,从第2个倒入第1,3个等等……所以用两个for循环,可以遍历出所有的倒水方案。
然后注意一些不能倒水的条件,比如要倒的杯子是空的,目标杯子是满的,则不进行倒水的动作。
#include<cstdio>#include<ctype.h>#include<algorithm>#include<iostream>#include<cstring>#include<vector>#include<stack>#include<cmath>#include<queue>#include<set>using namespace std;#define ll long long#define NMAX 20000typedef int state[3];state st[NMAX],a;int pour[NMAX];int record[205];int target;int vis[205][205],vispour[205][205];int try_to_insert(int x,int tpour){state &k = st[x];if(vis[k[0]][k[1]] != 1 || vispour[k[0]][k[1]] > tpour){vis[k[0]][k[1]] = 1;vispour[k[0]][k[1]] = tpour;return 1;}return 0;}int main(){// freopen("input.txt","r",stdin);// freopen("o.txt","w",stdout);int i,j,t,ans;scanf("%d",&t);while(t--){memset(record,0,sizeof(record));memset(vis,0,sizeof(vis));memset(vispour,0,sizeof(vis));scanf("%d%d%d%d",&a[0],&a[1],&a[2],&target);st[1][0] = st[1][1] = 0;st[1][2] = a[2];memset(pour,0,sizeof(pour));record[a[2]] = 1;int front = 1,rear = 2;vis[0][0] = 1;bool flag = false;while(front < rear){for(i = 0; i < 3; i++)if(record[st[front][i]] == 0 || pour[record[st[front][i]]] > pour[front])record[st[front][i]] = front;for(i = 0; i < 3; i++)if(st[front][i] == target){if(flag)ans = pour[ans] > pour[front]?front:ans;elseans = front;flag = true;break;}for(i = 0; i < 3; i++){state &w = st[front];if(w[i] != 0){for(j = 0; j < 3; j++){if(i == j || (i != j && w[j] == a[j])) continue;state &temp = st[rear];memcpy(temp,w,sizeof(w));int pp;if(w[i] + w[j] > a[j]){pp = a[j] - w[j];temp[i] = w[i] - pp;temp[j] = a[j];}else{pp = w[i];temp[i] = 0;temp[j] = w[j] + pp;}int tpour;tpour = pour[front] + pp;if(try_to_insert(rear,tpour)){pour[rear] = tpour;rear++;}}}}front++;}if(record[target] == 0){for(i = target; record[i] == 0; i--);printf("%d %d\n",pour[record[i]],i);}else printf("%d %d\n",pour[ans],target);}return 0;}
标签: spfa
题目大意
有n个村庄和m个城堡,村庄编号从1开始,城堡编号从n+1开始,一个人带着公主要从城堡n+m到村庄1,他还有一个魔法鞋可以有cnt次的使用机会可以让人能不花费时间走最多l,人只能在路上没有城堡的时候使用这个魔法鞋,问最少花费多少时间能到达村庄1。
解题思路
最短路径问题,用spfa算法,先用floyd将地点i到j的最短距离求出(不经过城堡),然后用f[i][j]表示到达结点i还剩j次穿魔法鞋机会的花费时间,与普通的spfa不同的是加了一个判断:f[u][t1] > f[i][t1-1],意味着从u到i用一次魔法鞋如果可以减短时间就用掉,并且如果不再队列中就加到队尾。
#include<cstdio>#include<cstring>#include<string>#include<queue>#include<algorithm>#include<map>#include<stack>#include<iostream>#include<list>#include<set>#include<cmath>#define INF 0x7fffffff#define eps 1e-6#define LL long longusing namespace std;int a,b,m,l,k,n;struct lx{int v,len;};vector<lx>g[101];int dis[101][101];void SPFA(int start){queue<int>q;bool vis[101];memset(vis,0,sizeof(vis));q.push(start);vis[start]=1;dis[start][start]=0;while(!q.empty()){int u=q.front();q.pop();vis[u]=0;for(int j=0;j<g[u].size();j++){int v=g[u][j].v;int len=g[u][j].len;if(dis[start][v]>dis[start][u]+len){dis[start][v]=dis[start][u]+len;if(v<=a&&!vis[v]){vis[v]=1;q.push(v);}}}}}void spfa(){bool vis[101];int dp[101][11];for(int i=0;i<101;i++){vis[i]=0;for(int j=0;j<11;j++)dp[i][j]=INF;}queue<int>q;q.push(n);vis[n]=1;dp[n][k]=0;while(!q.empty()){int u=q.front();q.pop();vis[u]=0;for(int i=0;i<=k;i++){for(int j=0;j<g[u].size();j++){int v=g[u][j].v;int len=g[u][j].len;if(dp[u][i]!=INF&&dp[v][i]>dp[u][i]+len){dp[v][i]=dp[u][i]+len;if(!vis[v]){vis[v]=1;q.push(v);}// printf("%d > %d+%d\n",dp[v][i],dp[u][i],len);// dp[u][i]!=INF;注意}if(i==0)continue;for(v=1;v<=n;v++){if(v!=u&&dis[u][v]<=l){if(dp[v][i-1]>dp[u][i]){dp[v][i-1]=dp[u][i];if(!vis[v]){vis[v]=1;q.push(v);}}}}}}}int ans=INF;for(int i=0;i<=k;i++)ans=min(ans,dp[1][i]);printf("%d\n",ans);}int main(){int t;scanf("%d",&t);while(t--){scanf("%d%d%d%d%d",&a,&b,&m,&l,&k);for(int i=0;i<101;i++)g[i].clear();n=a+b;int u,v,len;while(m--){scanf("%d%d%d",&u,&v,&len);lx now;now.len=len;now.v=v,g[u].push_back(now);now.v=u,g[v].push_back(now);}for(int i=0;i<101;i++)for(int j=0;j<101;j++)dis[i][j]=INF;for(int i=1;i<=n;i++)SPFA(i);spfa();}}