/*
POJ 3268
题目大意是给出一个有向图的带权邻接矩阵,然后给定目标节点X,求出其余结点出发到结点X再从X回到出发结点的最短路径和中最大的那个...
把矩阵转置一下就好了,转置以后就又相当于从X出发了,再来一次Dijkstra搞定...很好理解的..
*/
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1010;
const int MAX=1000001;
int n,m;
int map1[N][N];
int map2[N][N],visited[N];
int dist1[N],dist2[N];
void dijkstra(int mapx[][N],int dist[],int x){//最短路径
int u,minx;
for(int i=1;i<=n;i++)
dist[i]=mapx[x][i];
memset(visited,0,sizeof(visited));
visited[x]=1;
for(int i=1;i<=n;i++){
u=x,minx=MAX;
for(int j=1;j<=n;j++){
if(!visited[j]&&dist[j]<minx){
minx=dist[j];
u=j;
}
}
visited[u]=1;
for(int j=1;j<=n;j++){
if(!visited[j]&&dist[j]>dist[u]+mapx[u][j])
dist[j]=dist[u]+mapx[u][j];
}
}
}
int main(){
int ai,bi,ti,x;
int ans=0;
scanf("%d%d%d",&n,&m,&x);
for(int i=1;i<=n;i++){//初始化
for(int j=1;j<=n;j++){
if(i==j)
{
map1[i][j]=0;
map2[j][i]=0;
}
else
{
map1[i][j]=MAX;
map2[j][i]=MAX;
}
}
}
for(int i=1;i<=m;i++){
scanf("%d%d%d",&ai,&bi,&ti);
map1[ai][bi]=ti;
map2[bi][ai]=ti;//转置矩阵
}
dijkstra(map1,dist1,x);
dijkstra(map2,dist2,x);
for(int i=1;i<=n;i++){
if(ans<dist1[i]+dist2[i])
ans=dist1[i]+dist2[i];
}
printf("%d\n",ans);
}
/*
题目要我们求是否存在一条路,FJ重新回到起点之后时间回到了过去,就是让我们判断在图中是否存在负权回路。
我用了SPFA,当一个点入队超过n次时,可以判断图中存在负权回路。
注意图中的前m条路是双向的,注意处理
后面的w条虫洞是单向的。
POJ 3259
*/
#include<cstdio>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
#define MAXN 550
#define INF 0x7fffffff
struct node{
int to;//终点
int dis;//距离
};
bool in[MAXN];//是否在队列
int counts[MAXN],dis[MAXN],n,m,w;// counts入队的次数、dis最短的距离
vector<node>g[MAXN];
bool spfa(int s){//模板题
queue<int>q;
for(int i=1;i<=n;i++){
dis[i]=INF;
counts[i]=0;
in[i]=false;
}
dis[s]=0;
counts[s]=1;
in[s]=true;
q.push(s);
while(!q.empty()){
int tag=q.front();
q.pop();
in[tag]=false;
for(int i=0;i<g[tag].size();i++){
int j=g[tag][i].to;
if(g[tag][i].dis+dis[tag]<dis[j]){//更新路径
dis[j]=g[tag][i].dis+dis[tag];
if(!in[j]){//不在队列入队
in[j]=true;
counts[j]++;
if(counts[j]>=n)//存在负环路
return false;
q.push(j);
}
}
}
}
return true;
}
void init(){ //初始化数据
scanf("%d%d%d",&n,&m,&w);
int x,y,d;
node temp;
for(int i=0;i<=n;i++)//清空操作
g[i].clear();
for(int i=1;i<=m;i++){
scanf("%d%d%d",&x,&y,&d);//双向边
temp.to=y;
temp.dis=d;
g[x].push_back(temp);
temp.to=x;
g[y].push_back(temp);
}
for(int i=1;i<=w;i++){
scanf("%d%d%d",&x,&y,&d);//单向边 只能回到过去
temp.to=y;
temp.dis=-d;
g[x].push_back(temp);
}
}
int main(){
int t ;
scanf("%d",&t);
while(t--){
init();
if(spfa(1))
printf("NO\n");
else
printf("YES\n");
}
}
/*
POJ 2139
N头牛,拍了M部电影,同一部电影中的搭档们距离1,求最小度数之和。
题解:flyod最短路,枚举找最小
warshall_floyd算法,求任意两点间的最短路 O(V^3)
dp[i][j] = e(i, j)的权值(不存在为Inf,dp[i][i] = 0)
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int inf=0x3f3f3f3f;
int n,m,dp[303][303];
void warshall_floyd(){ //模板
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]);
}
int main(){
int ans=inf;
scanf("%d%d",&n,&m);
//初始化
memset(dp,inf,sizeof(dp));
for(int i=1;i<n;i++)
dp[i][i]=0;
while(m--){
int a,b[303];
scanf("%d",&a);
for(int i=0;i<a;i++)
scanf("%d",&b[i]);
for(int i=0;i<a-1;i++)
for(int j=i+1;j<a;j++){
dp[b[i]][b[j]]=dp[b[j]][b[i]]=1;
}
}
warshall_floyd();
for(int i=1;i<=n;i++){//枚举类型
int sum=0;
for(int j=1;j<=n;j++)
sum+=dp[i][j];
ans=min(ans,sum);
}
printf("%d\n",ans*100/(n-1));
}
/*
POJ 1062
最短路径——Dijkstra算法
此题的关键在于等级限制的处理,最好的办法是采用枚举,即假设酋长等级为5,等级限制为2,那么需要枚举等级从3~5,4~6,5~7
从满足改等级范围的结点组成的子图中用Dijkstra来算出最短路径
小结,通过枚举的方式可以消除一些图与图之间的限制
[lev-M,lev],[lev-M+1,lev+1],... ...,[lev,lev+M]
*/
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
#define INF 0x3f3f3f3f
#define MAXN 101
using namespace std;
int dict[MAXN][MAXN],lev[MAXN],d[MAXN],value[MAXN];
bool within_lim[MAXN],v[MAXN];//within_lim为满足等级限制的标记数组
int lev_lim,n;
int dijkstra(){
int mininum=INF;
memset(v,0,sizeof(v));//清除所有点的标号
for(int i=1;i<=n;i++)//设d[0] = 0,其他d[i] = INF
d[i]=(i==1?0:INF);
for(int i=1;i<=n;i++){//循环N次
int x=0,m=INF;
for(int j=1;j<=n;j++){
if(!v[j]&&d[j]<=m&&within_lim[j]){//在所有未标号且满足等级限制的结点中,选出d值最小的结点x
x=j;
m=d[j];
}
}
v[x]=1;//给结点x标记
for(int j=1;j<=n;j++){
if(within_lim[j]){//对于从x出发的所有边(x,y),更新d[y] = min{d[y], d[x] + map[x][y])
d[j]=min(d[j],d[x]+dict[x][j]);//满足等级限制
}
}
}
for(int i=1;i<=n;i++){
d[i]+=value[i];
if(d[i]<mininum)//对于每个d[i]值,还需加上进入该结点的花费,再进行比较
mininum=d[i];
}
return mininum;
}
int main(){
scanf("%d%d",&lev_lim,&n);
for(int i=0;i<=n;i++)
for(int j=0;j<=n;j++)
dict[i][j]=(i==j?0:INF);//图的初始化,注意对角线初始化为0,从自己出发到自己的花费为0
for(int i=1;i<=n;i++){
int t;
scanf("%d%d%d",&value[i],&lev[i],&t);
for(int j=1;j<=t;j++){
int k;
scanf("%d",&k);
scanf("%d",&dict[i][k]);
}//建图完毕
}
int kinglev=lev[1];
int min_cost=INF,cost;
for(int i=0;i<=lev_lim;i++){
memset(within_lim,0,sizeof(within_lim));//初始化标记数组
for(int j=1;j<=n;j++){//枚举等级允许范围的结点
if(lev[j]>=kinglev-lev_lim+i&&lev[j]<=kinglev+i)
within_lim[j]=1;
}
cost=dijkstra();
if(cost<min_cost)
min_cost=cost;
}
printf("%d\n",min_cost);
}
/*
POJ 2240
*/
#include<cstdio>
#include<map>
#include<string>
#define INF 0x3f3f3f3f
using namespace std;
char money[30];
char change1[30],change2[30];
double trans;
double dict[50][50];
int n,m;
map<string,int>p;//用map建立字符串与编号之间的关系(巧用)
void Floyd(){
for(int k=1;k<=n;k++)
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++){
if(dict[i][j]<dict[i][k]*dict[k][j]) //变形的最大路径 把‘+’变为了‘*’
dict[i][j]=dict[i][k]*dict[k][j];
}
}
void solve(){
int cnt=1;
while(~scanf("%d%*c",&n)&&n){
for(int i=1;i<=n;i++){
scanf("%s",money);
p[money]=i;
dict[i][i]=1;
}
scanf("%d%*c",&m);
for(int i=1;i<=m;i++){
scanf("%s%lf%s",change1,&trans,change2);
dict[p[change1]][p[change2]]=trans;
}
Floyd();
bool flag=false;
for(int i=1;i<=n;i++){
if(dict[i][i]>1){
flag=true;
break;
}
}
if(flag)
{
printf("Case %d: Yes\n", cnt++);
}
else
{
printf("Case %d: No\n", cnt++);
}
}
}
int main()
{
solve();
return 0;
}
/*
POJ 1860
题意 : 就是套汇的问题,汇率Rab, 增加了一个手续费 Cab 。。。。。。。每次的结果是 (本金 - 手续费) * 汇率,而且一个人拥有的钱的类型是已知的,拥有的value 钱的个数也是已知的, 问你能不能增值。
输入 :
3 2 1 20.0 //钱种类个数 汇率的个数,拥有第几种钱, 拥有多少钱
1 2 1.00 1.00 1.00 1.00 //钱a, 钱b, rab, cab, rba, cba
2 3 1.10 1.00 1.10 1.00
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct Edge{
int s,e;
double r;
double c;
}edge[210];
int k;
int N,M,S;
double V;
double dis[110];
bool bellman_ford(){
bool sign;
memset(dis,0,sizeof(dis));
dis[S]=V;
for(int j=0;j<N+1;j++){//N+1 如果每次都有改变的话,说明一定存在环路。
sign=false;
for(int i=0;i<k;i++){
if(dis[edge[i].e]<(dis[edge[i].s]-edge[i].c)*edge[i].r){
dis[edge[i].e]=(dis[edge[i].s]-edge[i].c)*edge[i].r;
sign=true;
}
}
if(!sign)
break;
}
if(sign)
return false;
else
return true;
}
int main(){
while(~scanf("%d%d%d%lf",&N,&M,&S,&V)){
k=0;
int a,b;
double rab,cab,rba,cba;
for(int i=0;i<M;i++){
scanf("%d%d%lf%lf%lf%lf",&a,&b,&rab,&cab,&rba,&cba);
edge[k].s=a;
edge[k].e=b;
edge[k].r=rab;
edge[k++].c=cab;
edge[k].s=b;
edge[k].e=a;
edge[k].r=rba;
edge[k++].c=cba;
}
if(bellman_ford())
puts("NO");
else
puts("YES");
}
}
/*
POJ 2253
//如果存在路径,则选择路径中最长的边来更新即可
*/
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=210;
const double MAX=2000;
double dict[maxn][maxn];
double dis[maxn];
int visited[maxn];
int n;
double ans;
struct Point{
double x,y;
}p[maxn];
double dist(Point a,Point b){
return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
}
void Dijkstra(){
for(int i=1;i<=n;i++)
dis[i]=MAX;
dis[1]=0;
memset(visited,0,sizeof(visited));
for(int i=1;i<=n;i++){
int x;
double minx=MAX;
for(int j=1;j<=n;j++){
if(!visited[j]&&dis[j]<=minx){
minx=dis[j];
x=j;
}
}
visited[x]=1;
if(ans<dis[x]&&dis[x]!=MAX)
ans=dis[x];
if(x==2)
return ;
for(int j=1;j<=n;j++){
if(!visited[j])
dis[j]=min(dis[j],dict[x][j]);
}
}
}
int main(){
int kcase=0;
while(scanf("%d",&n),n){
for(int i=1;i<=n;i++)
scanf("%lf%lf",&p[i].x,&p[i].y);
for(int i=1;i<=n;i++){
dict[i][i]=0;
for(int j=i+1;j<=n;j++){
dict[i][j] = dist(p[i],p[j]);
dict[j][i] = dist(p[i],p[j]);
}
}
ans=0;
Dijkstra();
printf("Scenario #%d\n", ++kcase);
printf("Frog Distance = %.3lf\n\n", ans);
}
}