ROADS (POJ1724)
N个城市,编号1到N。城市间有R条单向道路。
每条道路连接两个城市,有长度和过路费两个属性。
Bob只有K块钱,他想从城市1走到城市N。问最短共需要走多长的路。如果到不了N,输
出-1
2<=N<=100
0<=K<=10000
1<=R<=10000
每条路的长度 L, 1 <= L <= 100
每条路的过路费T , 0 <= T <= 100
输入:
K
N
R
s 1 e 1 L 1 T 1
s 1 e 2 L 2 T 2
…
s R e R L R T R
s e是路起点和终点
Sample Input
5
6
7
1 2 2 3
2 4 3 3
3 4 2 4
1 3 4 1
4 6 2 1
3 5 2 0
5 4 3 2
Sample Output
11
#include <iostream>
#include <cstring>
#include <vector>
#include <cstdio>
using namespace std;
struct rode
{
int d;int l;int t;
};
int minlen=1<<30,tallen,talcost;//当前最优路径长度,正在走的路的长度,花销
vector<vector<rode> > cityway(105);//cityway[i]是从i有路连接到的城市集合,二维数组
int visited[105];//判重标记,visited[i]=ture,表示i已经走过
int minl[105][10005];//minl[i][j]表示从1到i的,花销为j的最短路长度
int k,n,r;
void dfs(int s)//从s开始想n行走
{
if(s==n)
{
minlen=min(minlen,tallen);//更新最小值
return ;
}
for (int i=0;i<cityway[s].size();i++)
{
int d=cityway[s][i].d;//s有路连到d
if(!visited[d])
{//没走过的
int cost=cityway[s][i].t+talcost;
if (cost>k) continue;//剪枝
if (tallen + cityway[s][i].l>=minlen|| tallen+cityway[s][i].l>=minl[d][cost])//最优性剪枝
continue;
visited[i]=1;
tallen+=cityway[s][i].l;
talcost+=cityway[s][i].t;//更新数据
minl[d][cost]=tallen;
dfs(d);//从这路的终点再出发
visited[i]=0;//上个点不符合,则将上个点的数据清除
tallen-=cityway[s][i].l;
talcost-=cityway[s][i].t;
}
}
}
int main()
{
cin>>k>>n>>r;
for (int i=0;i<r;i++)
{
int s;
rode r;
cin>>s>>r.d>>r.l>>r.t;
if (s!=r.d)//起点和终点不同
cityway[s].push_back(r);//把r压进容器
}
for (int i=0;i<105;i++)
{
for(int j=0;j<10005;j++)
minl[i][j]=1<<30;//初始化为最大值无穷大
}
memset(visited,0,sizeof(visited));//标志清零
tallen=0; talcost=0;
minlen=1<<30;
visited[1]=1;//第一个走过
dfs(1);
if(minlen<(1<<30))//若改变了,比最大值小
cout<<minlen<<endl;
else cout<<"-1"<<endl;
return 0;
}
生日蛋糕 (POJ1190)
Description
7月17日是Mr.W的生日,ACM-THU为此要制作一个体积为Nπ的M层生日蛋糕,每层都是一个圆柱体。
设从下往上数第i(1 <= i <= M)层蛋糕是半径为Ri, 高度为Hi的圆柱。当i < M时,要求Ri > Ri+1且Hi > Hi+1。
由于要在蛋糕上抹奶油,为尽可能节约经费,我们希望蛋糕外表面(最下一层的下底面除外)的面积Q最小。
令Q = Sπ
请编程对给出的N和M,找出蛋糕的制作方案(适当的Ri和Hi的值),使S最小。
(除Q外,以上所有数据皆为正整数)
Input
有两行,第一行为N(N <= 10000),表示待制作的蛋糕的体积为Nπ;第二行为M(M <= 20),表示蛋糕的层数为M。
Output
仅一行,是一个正整数S(若无解则S = 0)。
Sample Input
100
2
Sample Output
68
Hint
圆柱公式
体积V = πR2H
侧面积A’ = 2πRH
底面积A = πR2
#include <iostream>
#include <cstring>
#include <cmath>
#include <stdlib.h>
using namespace std;
int n,m;
int area;//正在搭建的面积
int minarea=1<<30;//最优表面积
int minv[25];//minv[i],i层蛋糕最少的体积
int mina[25];//mina[i]i层蛋糕最少侧面积
int maxf(int n,int r,int h)
{
int v=0;
for (int i=0;i<n;i++)
v+=(r-i)*(r-i)*(h-i);//最大半径,高度,最大体积
return v;
}
void dfs(int v,int n,int r,int h)
{//要用n层去凑体积v,最底层半径不能超过r,高度不能超过h
if (n==0)
{//到顶了
if(v) return ;
else
{
minarea=min(minarea,area);//更新最小值
return;
}
}
if (v<=0) return ;//体积不存在
if(h<n||r<n) return;//最大半径,高度比层数小(最小半径高度)
if(minv[n]>v) return ;//当前体积小于最小体积
if(mina[n]+area>=minarea) return ;//当前面积比最小面积要大,剪枝
if(maxf(n,r,h)<v)
return ;//当前最大体积比要求的小
for (int rr=r;rr>=n;rr--)
{
if (n==m) area=rr*rr;//层数到了,底面积
for(int hh=h;hh>=n;hh--)
{
area+=hh*rr*2;//侧面积
dfs(v-rr*rr*hh,n-1,rr-1,hh-1);//减去当前体积剩的,层数-1,
area-=hh*rr*2;//不符合减去
}
}
}
int main()
{
cin>>n>>m;
minv[0]=0;
mina[0]=0;
for (int i=1;i<=m;i++)
{
minv[i]=minv[i-1]+i*i*i;//第i层半径至少为i,高度至少为i;
mina[i]=mina[i-1]+2*i*i;//2*pai*r*h
}
if (minv[m]>n)
cout<<0<<endl;
else
{//(总体积-最小体积)/最小半径*m,加一,为了向上取整
int maxh=(n-minv[m-1])/(m*m)+1;//底层最大高度
int maxr=sqrt((double)(n-minv[m-1])/m)+1;//底层最大半径
area=0; minarea=1<<30;
dfs(n,m,maxr,maxh);
if (minarea==1<<30)//未曾改变
cout<<0<<endl;
else cout<<minarea<<endl;
}
system("pause");
return 0;
}