[Hash] [最短路] [Vijos P1184] CoVH之华丽的IP伪装 (ConanIP)
2016-05-07 18:29
351 查看
这是一道神奇的题
这道题的题目说明全VJ最长……
这道题最让人看不懂……
这道题也是容易在CoVH模拟赛里卡死的一个…….
所以,我(负责任地)把所有说明打上来(可能加上各种吐槽)
Background 背景
挡在面前的铜墙铁壁
只要换一种思考方式也许就能变成一扇大门
唯一看穿真相的是一个看似小孩
智慧却过于常人的
他的名字就是名侦探柯南 //一看就柯南控出的题
Description 题目说明 //废话的开始,一脸茫然的起点
2006年4月4日 8:00 P.M
![](http://img.blog.csdn.net/20160507174940593)
![](http://img.blog.csdn.net/20160507174953490)
在这春暖花开, 阳光明媚的日子里, 柯南在”高效信息学在线评测系统”Vijos上切题目, 他兴高采烈的将刚刚拍完的程序提交上去, 突然发现前面排起了长长的队伍, 好多人在waiting, 又过一会, Vijos崩溃.
![](http://img.blog.csdn.net/20160507175005802)
柯南很快意识到这不是一个普通平常的, Vijos时常发生的系统不稳定现象, 而是一场有预谋的案件. 他找到Vivian Snow (16周岁).
——->
![](http://img.blog.csdn.net/20160507174922161)
(偶偷偷的说,这像不像喝了Aptx的Vvs?^_^)
Vivian Snow抱怨说:“ 已经是第二次了, 什么世道啊, 看我牛不顺眼啊!!”
柯南(·_·)问:“那么你当时记录下访问Vijos服务器的IP地址了么?”
Vivian Snow:” 这是自然的, 我把当时的记录拿给你看.”
柯南扫了一眼, 发现当时访问Vijos的众多IP中, 有一部分IP, 重复大量的向服务器投了巨大的数据包. 他意识到, 很可能是这些包将服务器挤爆的. 这种不算高明的手法居然把Vijos弄瘫痪了, 而攻击者很显然留下了大量证据, 只要追寻这些IP就可以了.
灰原哀忽然出现了:“ 江户川柯南, 你想得还真简单呢.”
柯南:“难道…… 难道你也在切Vijos……”
小哀:“现在没必要讨论这个了, 关键是攻击者很可能没用真实IP .”
柯南:“Er……”
柯南沉默良久, 之后缓缓站起身来:”* 如果我的推理没有错的话, 我们把访问过Vijos的IP地址调查一下, 找出当时它和哪些IP联络过, 筛选出向Vijos投过包的IP. 底下只考虑向Vijos投过包的IP, 对于两个直接联络过的IP, 他们发送的所有包的大小相加, 作为联络代价. 假定两个IP如果没有直接联络, 可以通过中间IP进行联络, 联络路径代价为联络路径中各段联络代价总和. 两个IP的联络代价为各条联络路径代价中最小的那个. 找出某一个投放过包IP地址使他与其他投放过包的IP联络代价总和最大, 那么这个IP地址就是攻击者的IP了 .”//只有这段关键
小哀:“你这个小迷糊还真不赖嘛, 可是你是怎样推理出的, 还有你怎么找出其他IP是否联络过呢?”
柯南:“我也不知道, Thunder叫我这么说的, 他说不这么说这题没法出了. 至于IP之间的联络情况, Thunder说他已经放在证据里了.”
小哀:“那么, 我去调查当时访问过Vijos的IP, 筛选出有嫌疑的.”
柯南:“等等, 话是这么说, 可是数据这么大……..”
小哀:“原来你也有犯难的时候, 你难道没发现有位大牛看我们对话很久了么.”
画外音:“那么就请看题的这位大牛帮助解决柯南的难题.”
看完这里,我整个人都是茫然的……
Input 输入
第一行 一个正整数N (N≤100000)
第2~N+1行, 每行一个IP地址 和一个正的整型数表示某个IP地址投放的包的大小
注意同一IP地址可能投放多次包, 至多不超过2000个IP地址
第N+2行 一个正整数M(M≤100000)
第N+3~M+N+2行, 每行两个IP地址用空格隔开, 表示两个IP地址之间有过联络,
不会出现两个IP多次联络的情况, 但会有IP访问2~N+1行未出现过IP的情况.
Output 输出
一行
![](http://img.blog.csdn.net/20160507175743565)
//编辑器打不出来了……
如果存在两个或以上的IP地址到其他IP的代价总和最大, 或者不能访问到其他所有投放包的IP, 那么认为攻击者无法确定, 则将攻击者的IP地址作为222.240.168.135处理//原来Vj的IP地址,不要随便Ping
这输入输出……
Sample Input 样例输入
4
222.134.7.28 7
61.74.218.22 8
60.191.255.98 4
219.153.2.168 5
5
222.134.7.28 61.74.218.22
222.134.7.28 60.191.255.98
222.134.7.28 219.153.2.168
61.74.218.22 219.153.2.168
222.134.7.28 213.87.4.23
//不要随便Ping,Ping不通的……
Sample Output 样例输出
The ONLY truth is: it is you, 60.191.255.98
Limits 限制
见题目
Time Limit : 2s & Memory Limit : 512MB
Hints 提示//其实是后记……
结局
最终, 攻击者被追查到了, 他居然是OIBH组织成员Gengar大牛.
Gengar被捕后的独白:” 曾经我沉迷于切Vijos, 但是每每我看到一个好题, 把它拍完, 提交的时候, 都看到了waiting长龙. 于是, 我下定决心, 既然Vijos不让我AC, 我就将Vijos毁灭. 后来, 我发现一个包可以引发一连串waiting, 十个包就是十连串, 一百万个包就足以使Vijos毁灭, 我的目的也就达成了. 小弟弟, 送你个包?”
可是无论如何逼供Gengar大牛对于组织内幕一概不招, 而Gengar大牛的机房也早已被组织处理. 柯南再一次和组织擦肩而过, 命运之轮继续旋转………
后记好有感觉…….
好了,开始做题
题里说啥来着……
翻译一下关键点:
如果我的推理没有错的话(你是出题人诶……), 我们把访问过Vijos的IP地址调查一下, 找出当时它和哪些IP联络过, 筛选出向Vijos投过包的IP. 底下只考虑向Vijos投过包的IP(没投过的忽略掉,投过的看成一个点), 对于两个直接联络过的IP(有边的点), 他们发送的所有包的大小相加, 作为联络代价(边为无向边,边权为连接的两个点权之和有种HLOI Magic的感觉). 假定两个IP如果没有直接联络, 可以通过中间IP进行联络(无向图), 联络路径代价为联络路径中各段联络代价总和. 两个IP的联络代价为各条联络路径代价中最小的那个(求最短路). 找出某一个投放过包IP地址使他与其他投放过包的IP联络代价总和最大(求到各个点最短路之和最大的点), 那么这个IP地址就是攻击者的IP了.
翻译完了,就是无向图,求到各个点最短路之和最大的点
哥,你是在讲故事吧……
把样例中的图放出来
//没有投包的忽略,IP地址取第一段
![](http://img.blog.csdn.net/20160507181359571)
现在的问题就是处理各种IP了
IP地址有四段(废话),要把它变成1,2,…的点,很容易想到哈希
搞定一个字符串哈希就好了……
给大家安利一个字符串哈希讲解,传送门
又调了半天,发现字符串哈希并不好用
哈希值过大,找编号的时候麻烦,果断放弃哈希……
(其实哈希是可以的)
还能怎么搞?STL的map
map是红黑树实现的,各种操作代价都是log2n的。2s可以霍霍……
最短路当属SPFA,总共时间复杂度约为n*m,还可以,但是常数比较非常大
又输入字符串……
这次放弃了哲学的读入,直接cin
还有一个小问题,如果存在两个或以上的IP地址到其他IP的代价总和最大, 或者不能访问到其他所有投放包的IP, 那么认为攻击者无法确定怎么搞
可以先把各个点的最短路径和求出来,再排一遍序。
情况1:第一个长度>=INT_MAX,就说明图不连通(这个可以在求和时处理)
情况2:第一个长度等于第二个长度,就说明违背了只有一个最大值,果断无法确定
正常这样就可以AC,但是细心的各位如果不放心,把关于投包的数组和dist数组扩到long long,就会发现WA一个点……
(我细心点有错吗?QAQ)
看了看数据,发现数据其实是有问题的
那个WA的点爆int了,数据生成的有问题……
好吧……这就是人品
上代码
数据已上传
这道题的题目说明全VJ最长……
这道题最让人看不懂……
这道题也是容易在CoVH模拟赛里卡死的一个…….
所以,我(负责任地)把所有说明打上来(可能加上各种吐槽)
Background 背景
挡在面前的铜墙铁壁
只要换一种思考方式也许就能变成一扇大门
唯一看穿真相的是一个看似小孩
智慧却过于常人的
他的名字就是名侦探柯南 //一看就柯南控出的题
Description 题目说明 //废话的开始,一脸茫然的起点
2006年4月4日 8:00 P.M
在这春暖花开, 阳光明媚的日子里, 柯南在”高效信息学在线评测系统”Vijos上切题目, 他兴高采烈的将刚刚拍完的程序提交上去, 突然发现前面排起了长长的队伍, 好多人在waiting, 又过一会, Vijos崩溃.
柯南很快意识到这不是一个普通平常的, Vijos时常发生的系统不稳定现象, 而是一场有预谋的案件. 他找到Vivian Snow (16周岁).
——->
(偶偷偷的说,这像不像喝了Aptx的Vvs?^_^)
Vivian Snow抱怨说:“ 已经是第二次了, 什么世道啊, 看我牛不顺眼啊!!”
柯南(·_·)问:“那么你当时记录下访问Vijos服务器的IP地址了么?”
Vivian Snow:” 这是自然的, 我把当时的记录拿给你看.”
柯南扫了一眼, 发现当时访问Vijos的众多IP中, 有一部分IP, 重复大量的向服务器投了巨大的数据包. 他意识到, 很可能是这些包将服务器挤爆的. 这种不算高明的手法居然把Vijos弄瘫痪了, 而攻击者很显然留下了大量证据, 只要追寻这些IP就可以了.
灰原哀忽然出现了:“ 江户川柯南, 你想得还真简单呢.”
柯南:“难道…… 难道你也在切Vijos……”
小哀:“现在没必要讨论这个了, 关键是攻击者很可能没用真实IP .”
柯南:“Er……”
柯南沉默良久, 之后缓缓站起身来:”* 如果我的推理没有错的话, 我们把访问过Vijos的IP地址调查一下, 找出当时它和哪些IP联络过, 筛选出向Vijos投过包的IP. 底下只考虑向Vijos投过包的IP, 对于两个直接联络过的IP, 他们发送的所有包的大小相加, 作为联络代价. 假定两个IP如果没有直接联络, 可以通过中间IP进行联络, 联络路径代价为联络路径中各段联络代价总和. 两个IP的联络代价为各条联络路径代价中最小的那个. 找出某一个投放过包IP地址使他与其他投放过包的IP联络代价总和最大, 那么这个IP地址就是攻击者的IP了 .”//只有这段关键
小哀:“你这个小迷糊还真不赖嘛, 可是你是怎样推理出的, 还有你怎么找出其他IP是否联络过呢?”
柯南:“我也不知道, Thunder叫我这么说的, 他说不这么说这题没法出了. 至于IP之间的联络情况, Thunder说他已经放在证据里了.”
小哀:“那么, 我去调查当时访问过Vijos的IP, 筛选出有嫌疑的.”
柯南:“等等, 话是这么说, 可是数据这么大……..”
小哀:“原来你也有犯难的时候, 你难道没发现有位大牛看我们对话很久了么.”
画外音:“那么就请看题的这位大牛帮助解决柯南的难题.”
看完这里,我整个人都是茫然的……
Input 输入
第一行 一个正整数N (N≤100000)
第2~N+1行, 每行一个IP地址 和一个正的整型数表示某个IP地址投放的包的大小
注意同一IP地址可能投放多次包, 至多不超过2000个IP地址
第N+2行 一个正整数M(M≤100000)
第N+3~M+N+2行, 每行两个IP地址用空格隔开, 表示两个IP地址之间有过联络,
不会出现两个IP多次联络的情况, 但会有IP访问2~N+1行未出现过IP的情况.
Output 输出
一行
//编辑器打不出来了……
如果存在两个或以上的IP地址到其他IP的代价总和最大, 或者不能访问到其他所有投放包的IP, 那么认为攻击者无法确定, 则将攻击者的IP地址作为222.240.168.135处理//原来Vj的IP地址,不要随便Ping
这输入输出……
Sample Input 样例输入
4
222.134.7.28 7
61.74.218.22 8
60.191.255.98 4
219.153.2.168 5
5
222.134.7.28 61.74.218.22
222.134.7.28 60.191.255.98
222.134.7.28 219.153.2.168
61.74.218.22 219.153.2.168
222.134.7.28 213.87.4.23
//不要随便Ping,Ping不通的……
Sample Output 样例输出
The ONLY truth is: it is you, 60.191.255.98
Limits 限制
见题目
Time Limit : 2s & Memory Limit : 512MB
Hints 提示//其实是后记……
结局
最终, 攻击者被追查到了, 他居然是OIBH组织成员Gengar大牛.
Gengar被捕后的独白:” 曾经我沉迷于切Vijos, 但是每每我看到一个好题, 把它拍完, 提交的时候, 都看到了waiting长龙. 于是, 我下定决心, 既然Vijos不让我AC, 我就将Vijos毁灭. 后来, 我发现一个包可以引发一连串waiting, 十个包就是十连串, 一百万个包就足以使Vijos毁灭, 我的目的也就达成了. 小弟弟, 送你个包?”
可是无论如何逼供Gengar大牛对于组织内幕一概不招, 而Gengar大牛的机房也早已被组织处理. 柯南再一次和组织擦肩而过, 命运之轮继续旋转………
后记好有感觉…….
好了,开始做题
题里说啥来着……
翻译一下关键点:
如果我的推理没有错的话(你是出题人诶……), 我们把访问过Vijos的IP地址调查一下, 找出当时它和哪些IP联络过, 筛选出向Vijos投过包的IP. 底下只考虑向Vijos投过包的IP(没投过的忽略掉,投过的看成一个点), 对于两个直接联络过的IP(有边的点), 他们发送的所有包的大小相加, 作为联络代价(边为无向边,边权为连接的两个点权之和有种HLOI Magic的感觉). 假定两个IP如果没有直接联络, 可以通过中间IP进行联络(无向图), 联络路径代价为联络路径中各段联络代价总和. 两个IP的联络代价为各条联络路径代价中最小的那个(求最短路). 找出某一个投放过包IP地址使他与其他投放过包的IP联络代价总和最大(求到各个点最短路之和最大的点), 那么这个IP地址就是攻击者的IP了.
翻译完了,就是无向图,求到各个点最短路之和最大的点
哥,你是在讲故事吧……
把样例中的图放出来
//没有投包的忽略,IP地址取第一段
现在的问题就是处理各种IP了
IP地址有四段(废话),要把它变成1,2,…的点,很容易想到哈希
搞定一个字符串哈希就好了……
给大家安利一个字符串哈希讲解,传送门
又调了半天,发现字符串哈希并不好用
哈希值过大,找编号的时候麻烦,果断放弃哈希……
(其实哈希是可以的)
还能怎么搞?STL的map
map是红黑树实现的,各种操作代价都是log2n的。2s可以霍霍……
最短路当属SPFA,总共时间复杂度约为n*m,还可以,但是常数比较非常大
又输入字符串……
这次放弃了哲学的读入,直接cin
还有一个小问题,如果存在两个或以上的IP地址到其他IP的代价总和最大, 或者不能访问到其他所有投放包的IP, 那么认为攻击者无法确定怎么搞
可以先把各个点的最短路径和求出来,再排一遍序。
情况1:第一个长度>=INT_MAX,就说明图不连通(这个可以在求和时处理)
情况2:第一个长度等于第二个长度,就说明违背了只有一个最大值,果断无法确定
正常这样就可以AC,但是细心的各位如果不放心,把关于投包的数组和dist数组扩到long long,就会发现WA一个点……
(我细心点有错吗?QAQ)
看了看数据,发现数据其实是有问题的
那个WA的点爆int了,数据生成的有问题……
好吧……这就是人品
上代码
#include <map> #include <queue> #include <cstdio> #include <cstring> #include <climits> #include <iostream> #include <algorithm> #define MAXN 2010 #define MAXM 80010 using namespace std; struct node { int pt; long long best_dis; }; bool cmp(node a,node b) { return a.best_dis>b.best_dis; } int ip_num,n,m; int tmp; string ip[MAXN],tmpip; int dist[MAXN]; bool vis[MAXN]; int a[MAXN]; int head[MAXN],nex[MAXM],to[MAXM],cnt = 0; int wei[MAXM]; node best[MAXN]; map <string,int> hash_table; queue <int> q; int spfa(int src) { while (!q.empty()) q.pop(); q.push(src); memset(vis, false, sizeof(vis)); for (int i=1;i<=n;i++) dist[i]=INT_MAX; vis[src]=true;dist[src]=0; while(!q.empty()) { int u = q.front(); q.pop(); vis[u] = false; for(int i = head[u]; i != -1; i = nex[i]) { int v = to[i]; if(v == 0) continue; if(dist[v] > dist[u] + wei[i]) { dist[v] = dist[u] + wei[i]; if(!vis[v]) { q.push(v); vis[v] = true; } } } } int ans=0; for (int i=1;i<=n;i++) { if (dist[i]==INT_MAX) return INT_MAX; else ans+=dist[i]; } return ans; } void add(int u, int v, long long w) { nex[cnt] = head[u]; to[cnt] = v; wei[cnt] = w; head[u] = cnt++; } int main() { memset(head,-1,sizeof(head)); cin>>ip_num; for (int i=1;i<=ip_num;i++) { cin>>tmpip>>tmp; if (hash_table[tmpip]) a[hash_table[tmpip]]+=tmp; else { n++; hash_table[tmpip]=n; a[hash_table[tmpip]]=tmp; ip =tmpip; } } cin>>m; for (int i=1;i<=m;i++) { string tmp1,tmp2; cin>>tmp1>>tmp2; if (hash_table[tmp1]&&hash_table[tmp2]) { add(hash_table[tmp1],hash_table[tmp2],a[hash_table[tmp1]]+a[hash_table[tmp2]]); add(hash_table[tmp2],hash_table[tmp1],a[hash_table[tmp1]]+a[hash_table[tmp2]]); } } for (int i=1;i<=n;i++) { best[i].best_dis=spfa(i); best[i].pt=i; } sort(best+1,best+n+1,cmp); if (best[1].best_dis==INT_MAX||best[1].best_dis==best[2].best_dis) printf("The ONLY truth is: it is you, 222.240.168.135\n"); else { printf("The ONLY truth is: it is you, "); cout<<ip[best[1].pt]<<endl; } return 0; }
数据已上传
相关文章推荐
- 6、udev机制
- 5、映射的思考
- 最详细的Log4j使用教程
- 二叉树的序列化和反序列化
- Mac OSX配置Android Studio开发软件
- 7、字符设备系统
- Yii-Unable to verify your data submission 错误(CSRF)
- poj 2425 A Chess Game(sg函数)
- 一篇告诫正在学习以及将要学习计算机的同学的文章【找不到原作者及出处非常抱歉】
- 常见计算机英文汇总
- shell script 学习
- Oracle学习系列1-7
- Butter Knife的使用(仅限Android Studio)
- cocos2d-x游戏开发实例(一)
- Junit4 单元测试 private 私有方法 abstract类
- 一个屌丝程序猿的人生(五)
- 安卓学习记录03
- Java多线程
- cmd 命令行小记
- ListView用单行刷新取代notifyDataSetChanged